Update display code

Use Custom DMA code
Fis small SD card issues
pull/34/head
DiSlord Live 4 years ago
parent c224fa9af6
commit 5ce2e66bcf

@ -1,4 +1,6 @@
/*
* Copyright (c) 2019-2020, Dmitry (DiSlord) dislordlive@gmail.com
* Based on TAKAHASHI Tomohiro (TTRFTECH) edy555@gmail.com
* All rights reserved.
*
* This is free software; you can redistribute it and/or modify
@ -74,7 +76,11 @@
#define SD_INIT_SPI_SPEED SPI_BR_DIV256
// Disable DMA rx on disabled DMA tx
#ifndef __USE_DISPLAY_DMA__
#ifdef __USE_DISPLAY_DMA__
// DMA channels for used in LCD SPI bus
#define LCD_DMA_RX DMA1_Channel2 // DMA1 channel 2 use for SPI1 rx
#define LCD_DMA_TX DMA1_Channel3 // DMA1 channel 3 use for SPI1 tx
#else
#undef __USE_DISPLAY_DMA_RX__
#endif
@ -203,11 +209,11 @@ void spi_TxWord(uint16_t data) {
}
// Transmit buffer to SPI bus (len should be > 0)
void spi_TxBuffer(uint8_t *buffer, uint16_t len) {
do {
void spi_TxBuffer(const uint8_t *buffer, uint16_t len) {
while(len--) {
while (SPI_TX_IS_NOT_EMPTY(LCD_SPI));
SPI_WRITE_8BIT(LCD_SPI, *buffer++);
}while(--len);
}
}
// Receive byte from SPI bus
@ -227,7 +233,7 @@ void spi_RxBuffer(uint8_t *buffer, uint16_t len) {
}while(--len);
}
void spi_DropRx(void){
void spi_DropRx(void) {
// Drop Rx buffer after tx and wait tx complete
while (SPI_RX_IS_NOT_EMPTY(LCD_SPI)||SPI_IS_BUSY(LCD_SPI))
(void)SPI_READ_8BIT(LCD_SPI);
@ -238,81 +244,43 @@ void spi_DropRx(void){
// SPI DMA settings and data
//*****************************************************
#ifdef __USE_DISPLAY_DMA__
static const stm32_dma_stream_t *dmatx =
STM32_DMA_STREAM(STM32_SPI_SPI1_TX_DMA_STREAM);
static const uint32_t txdmamode =
STM32_DMA_CR_CHSEL(SPI1_TX_DMA_CHANNEL) // Select SPI1 Tx DMA
static const uint32_t txdmamode = 0
| STM32_DMA_CR_PL(STM32_SPI_SPI1_DMA_PRIORITY) // Set priority
| STM32_DMA_CR_DIR_M2P; // Memory to Spi
// Not handle interrupt
#if 0
static void spi_lld_serve_tx_interrupt(SPIDriver *spip, uint32_t flags)
{
(void)spip;
(void)flags;
}
#endif
static const stm32_dma_stream_t *dmarx = STM32_DMA_STREAM(STM32_SPI_SPI1_RX_DMA_STREAM);
static const uint32_t rxdmamode =
STM32_DMA_CR_CHSEL(SPI1_RX_DMA_CHANNEL) // Select SPI1 Rx DMA
static const uint32_t rxdmamode = 0
| STM32_DMA_CR_PL(STM32_SPI_SPI1_DMA_PRIORITY) // Set priority
| STM32_DMA_CR_DIR_P2M; // SPI to Memory
// Not handle interrupt
#if 0
static void spi_lld_serve_rx_interrupt(SPIDriver *spip, uint32_t flags)
{
(void)spip;
(void)flags;
// SPI transmit byte buffer use DMA (65535 bytes limit)
static inline void spi_DMATxBuffer(const uint8_t *buffer, uint16_t len, bool wait) {
dmaChannelSetMemory(LCD_DMA_TX, buffer);
dmaChannelSetTransactionSize(LCD_DMA_TX, len);
dmaChannelSetMode(LCD_DMA_TX, txdmamode | STM32_DMA_CR_BYTE | STM32_DMA_CR_MINC | STM32_DMA_CR_EN);
if (wait)
dmaChannelWaitCompletion(LCD_DMA_TX);
}
#endif
// Send prepared DMA data, and wait completion
static void dmaStreamFlush(uint32_t len)
{
while (len) {
// DMA data transfer limited by 65535
uint16_t tx_size = len > 65535 ? 65535 : len;
dmaStreamSetTransactionSize(dmatx, tx_size);
dmaStreamEnable(dmatx);
len -= tx_size;
dmaWaitCompletion(dmatx);
}
// Wait DMA Rx completion
static void dmaChannelWaitCompletionRxTx(void){
dmaChannelWaitCompletion(LCD_DMA_TX);
dmaChannelWaitCompletion(LCD_DMA_RX);
while (SPI_IS_BUSY(LCD_SPI)); // Wait SPI tx/rx
}
// SPI receive byte buffer use DMA
void spi_DMATxBuffer(uint8_t *buffer, uint16_t len) {
dmaStreamSetMemory0(dmatx, buffer);
dmaStreamSetMode(dmatx, txdmamode | STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE | STM32_DMA_CR_MINC);
dmaStreamFlush(len);
}
static void dmaWaitCompletionRxTx(void){
// Wait DMA completion
dmaWaitCompletion(dmatx);
dmaWaitCompletion(dmarx);
}
// SPI transmit byte buffer use DMA
void spi_DMARxBuffer(uint8_t *buffer, uint16_t len, bool wait) {
uint8_t dummy_tx = 0xFF;
// Init Rx DMA buffer, size, mode (spi and mem data size is 8 bit)
dmaStreamSetMemory0(dmarx, buffer);
dmaStreamSetTransactionSize(dmarx, len);
dmaStreamSetMode(dmarx, rxdmamode | STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE | STM32_DMA_CR_MINC);
// Init dummy Tx DMA (for rx clock), size, mode (spi and mem data size is 8 bit)
dmaStreamSetMemory0(dmatx, &dummy_tx);
dmaStreamSetTransactionSize(dmatx, len);
dmaStreamSetMode(dmatx, txdmamode | STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE);
// Skip SPI rx buffer
spi_DropRx();
// Start DMA exchange
dmaStreamEnable(dmarx);
dmaStreamEnable(dmatx);
static const uint16_t dummy_tx = 0xFFFF;
static inline void spi_DMARxBuffer(uint8_t *buffer, uint16_t len, bool wait) {
// Init Rx DMA buffer, size, mode (spi and mem data size is 8 bit), and start
dmaChannelSetMemory(LCD_DMA_RX, buffer);
dmaChannelSetTransactionSize(LCD_DMA_RX, len);
dmaChannelSetMode(LCD_DMA_RX, rxdmamode | STM32_DMA_CR_BYTE | STM32_DMA_CR_MINC | STM32_DMA_CR_EN);
// Init dummy Tx DMA (for rx clock), size, mode (spi and mem data size is 8 bit), and start
dmaChannelSetMemory(LCD_DMA_TX, &dummy_tx);
dmaChannelSetTransactionSize(LCD_DMA_TX, len);
dmaChannelSetMode(LCD_DMA_TX, txdmamode | STM32_DMA_CR_BYTE | STM32_DMA_CR_EN);
if (wait)
dmaWaitCompletionRxTx();
dmaChannelWaitCompletionRxTx();
}
#endif // __USE_DISPLAY_DMA__
@ -326,25 +294,28 @@ void spi_init(void)
| LCD_SPI_SPEED // Baud rate control
// | SPI_CR1_CPHA // Clock Phase
// | SPI_CR1_CPOL // Clock Polarity
;
;
LCD_SPI->CR2 = SPI_CR2_8BIT // SPI data size, set to 8 bit
| SPI_CR2_FRXTH; // SPI_SR_RXNE generated every 8 bit data
// | SPI_CR2_SSOE; //
| SPI_CR2_FRXTH // SPI_SR_RXNE generated every 8 bit data
// | SPI_CR2_SSOE //
#ifdef __USE_DISPLAY_DMA__
// Tx DMA init
dmaStreamAllocate(dmatx, STM32_SPI_SPI1_IRQ_PRIORITY, NULL, NULL);
dmaStreamSetPeripheral(dmatx, &LCD_SPI->DR);
LCD_SPI->CR2|= SPI_CR2_TXDMAEN; // Tx DMA enable
| SPI_CR2_TXDMAEN // Tx DMA enable
#ifdef __USE_DISPLAY_DMA_RX__
// Rx DMA init
dmaStreamAllocate(dmarx, STM32_SPI_SPI1_IRQ_PRIORITY, NULL, NULL);
dmaStreamSetPeripheral(dmarx, &LCD_SPI->DR);
// Enable DMA on SPI
LCD_SPI->CR2|= SPI_CR2_RXDMAEN; // Rx DMA enable
| SPI_CR2_RXDMAEN // Rx DMA enable
#endif
#endif
;
// Init SPI DMA Peripheral
#ifdef __USE_DISPLAY_DMA__
// Enable DMA, need for spi
rccEnableDMA1(false);
rccEnableDMA2(false);
dmaChannelSetPeripheral(LCD_DMA_TX, &LCD_SPI->DR); // DMA Peripheral Tx
#ifdef __USE_DISPLAY_DMA_RX__
dmaChannelSetPeripheral(LCD_DMA_RX, &LCD_SPI->DR); // DMA Peripheral Rx
#endif
#endif
// Enable DMA on SPI
LCD_SPI->CR1|= SPI_CR1_SPE; //SPI enable
}
@ -393,24 +364,18 @@ void set_SPI_mode(uint16_t mode){
// Disable inline for this function
static void send_command(uint8_t cmd, uint8_t len, const uint8_t *data)
{
// Uncomment on low speed SPI (possible get here before previous tx complete)
// while (SPI_IN_TX_RX(LCD_SPI));
#ifdef TINYSA4
set_SPI_mode(SPI_MODE_LCD);
#endif
while (SPI_IS_BUSY(LCD_SPI));
LCD_CS_LOW;
LCD_DC_CMD;
SPI_WRITE_8BIT(LCD_SPI, cmd);
// Need wait transfer complete and set data bit
while (SPI_IN_TX_RX(LCD_SPI))
;
// Send command data (if need)
while (SPI_IS_BUSY(LCD_SPI));
LCD_DC_DATA;
while (len-- > 0) {
while (SPI_TX_IS_NOT_EMPTY(LCD_SPI))
;
SPI_WRITE_8BIT(LCD_SPI, *data++);
}
spi_TxBuffer(data, len);
// while (SPI_IN_TX_RX(LCD_SPI));
//LCD_CS_HIGH;
}
@ -554,20 +519,24 @@ void ili9341_init(void)
LCD_CS_HIGH;
}
static void ili9341_setWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h){
static void ili9341_setWindow(uint8_t cmd, uint16_t x, uint16_t y, uint16_t w, uint16_t h){
// Any LCD exchange start from this
#ifdef __USE_DISPLAY_DMA__
dmaChannelWaitCompletionRxTx();
#endif
//uint8_t xx[4] = { x >> 8, x, (x+w-1) >> 8, (x+w-1) };
//uint8_t yy[4] = { y >> 8, y, (y+h-1) >> 8, (y+h-1) };
uint32_t xx = __REV16(x | ((x + w - 1) << 16));
uint32_t yy = __REV16(y | ((y + h - 1) << 16));
send_command(ILI9341_COLUMN_ADDRESS_SET, 4, (uint8_t *)&xx);
send_command(ILI9341_PAGE_ADDRESS_SET, 4, (uint8_t *)&yy);
send_command(cmd, 0, NULL);
}
#ifndef __USE_DISPLAY_DMA__
void ili9341_fill(int x, int y, int w, int h)
{
ili9341_setWindow(x, y, w, h);
send_command(ILI9341_MEMORY_WRITE, 0, NULL);
ili9341_setWindow(ILI9341_MEMORY_WRITE, x, y, w, h);
uint32_t len = w * h;
do {
while (SPI_TX_IS_NOT_EMPTY(LCD_SPI))
@ -576,21 +545,20 @@ void ili9341_fill(int x, int y, int w, int h)
}while(--len);
#ifdef __REMOTE_DESKTOP__
if (auto_capture) {
send_region("fill", x, y, w, h);
send_buffer((uint8_t *)&background_color, 2);
remote_region_t rd = {"fill\r\n", x, y, w, h};
send_region(&rd, (uint8_t *)&background_color, sizeof(pixel_t));
}
#endif
}
void ili9341_bulk(int x, int y, int w, int h)
{
ili9341_setWindow(x, y, w, h);
send_command(ILI9341_MEMORY_WRITE, 0, NULL);
ili9341_setWindow(ILI9341_MEMORY_WRITE, x, y, w, h);
spi_TxBuffer((uint8_t *)spi_buffer, w * h * sizeof(pixel_t));
#ifdef __REMOTE_DESKTOP__
if (auto_capture) {
send_region("bulk", x, y, w, h);
send_buffer((uint8_t *)spi_buffer, w *h * sizeof(pixel_t));
remote_region_t rd = {"bulk\r\n", x, y, w, h};
send_region(&rd, (uint8_t *)spi_buffer, w * h * sizeof(pixel_t));
}
#endif
}
@ -599,24 +567,26 @@ void ili9341_bulk(int x, int y, int w, int h)
//
// Use DMA for send data
//
#define LCD_DMA_MODE STM32_DMA_CR_HWORD
// Fill region by some color
void ili9341_fill(int x, int y, int w, int h)
{
#if 1
ili9341_setWindow(x, y ,w, h);
send_command(ILI9341_MEMORY_WRITE, 0, NULL);
dmaStreamSetMemory0(dmatx, &background_color);
dmaStreamSetMode(dmatx, txdmamode | STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD);
#endif
ili9341_setWindow(ILI9341_MEMORY_WRITE, x, y, w, h);
dmaChannelSetMemory(LCD_DMA_TX, &background_color);
uint32_t len = w * h, delta;
while(len) {
delta = len > 0xFFFF ? 0xFFFF : len; // DMA can send only 65535 data in one run
dmaChannelSetTransactionSize(LCD_DMA_TX, delta);
dmaChannelSetMode(LCD_DMA_TX, txdmamode | LCD_DMA_MODE | STM32_DMA_CR_EN);
dmaChannelWaitCompletion(LCD_DMA_TX);
len-=delta;
}
#ifdef __REMOTE_DESKTOP__
if (auto_capture) {
remote_region_t rd = {"fill\r\n", x, y, w, h};
send_region(&rd, (uint8_t *)&background_color, sizeof(pixel_t));
}
#endif
#if 1
dmaStreamFlush(w * h);
#endif
// while (SPI_IN_TX_RX(LCD_SPI));
}
@ -625,17 +595,11 @@ void ili9341_flip(bool flip) {
send_command(ILI9341_MEMORY_ACCESS_CONTROL, 1, &memAcc);
}
static void ili9341_DMA_bulk(uint16_t x, uint16_t y, uint16_t w, uint16_t h, pixel_t *buffer){
#if 1
ili9341_setWindow(x, y ,w, h);
send_command(ILI9341_MEMORY_WRITE, 0, NULL);
dmaStreamSetMemory0(dmatx, buffer);
dmaStreamSetMode(dmatx, txdmamode | STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_MINC);
dmaStreamSetTransactionSize(dmatx, w * h);
dmaStreamEnable(dmatx);
#endif
ili9341_setWindow(ILI9341_MEMORY_WRITE, x, y, w, h);
dmaChannelSetMemory(LCD_DMA_TX, buffer);
dmaChannelSetTransactionSize(LCD_DMA_TX, w * h);
dmaChannelSetMode(LCD_DMA_TX, txdmamode | LCD_DMA_MODE | STM32_DMA_CR_MINC | STM32_DMA_CR_EN);
#ifdef __REMOTE_DESKTOP__
if (auto_capture) {
remote_region_t rd = {"bulk\r\n", x, y, w, h};
@ -649,7 +613,7 @@ static void ili9341_DMA_bulk(uint16_t x, uint16_t y, uint16_t w, uint16_t h, pix
void ili9341_bulk(int x, int y, int w, int h)
{
ili9341_DMA_bulk(x, y, w, h, spi_buffer); // Send data
dmaWaitCompletion(dmatx);
dmaChannelWaitCompletion(LCD_DMA_TX); // Wait
}
// Used only in double buffer mode
@ -666,8 +630,8 @@ pixel_t *ili9341_get_cell_buffer(void){
// Wait completion before next data send
#ifndef ili9341_bulk_finish
void ili9341_bulk_finish(void){
dmaWaitCompletion(dmatx); // Wait DMA
//while (SPI_IN_TX_RX(LCD_SPI)); // Wait tx
dmaChannelWaitCompletion(LCD_DMA_TX); // Wait DMA
//while (SPI_IN_TX_RX(LCD_SPI)); // Wait tx
}
#endif
// Copy part of spi_buffer to region, no wait completion after if buffer count !=1
@ -687,8 +651,7 @@ void ili9341_bulk_continue(int x, int y, int w, int h)
void ili9341_read_memory(int x, int y, int w, int h, uint16_t *out)
{
uint16_t len = w * h;
ili9341_setWindow(x, y, w, h);
send_command(ILI9341_MEMORY_READ, 0, NULL);
ili9341_setWindow(ILI9341_MEMORY_READ, x, y, w, h);
// Skip data from rx buffer
spi_DropRx();
// Set read speed (if need different)
@ -719,7 +682,7 @@ void ili9341_read_memory(int x, int y, int w, int h, uint16_t *out)
// Parse received data to RGB565 format while data receive by DMA
uint8_t *rgbbuf = (uint8_t *)out;
do {
uint16_t left = dmaStreamGetTransactionSize(dmarx) + 3; // Get DMA data left
uint16_t left = dmaChannelGetTransactionSize(LCD_DMA_RX) + 3; // Get DMA data left
if (left > len) continue; // Next pixel RGB data not ready
do{ // Process completed by DMA data
uint8_t r, g, b; // read data is always 18bit in RGB888 format
@ -731,7 +694,7 @@ void ili9341_read_memory(int x, int y, int w, int h, uint16_t *out)
len -= 3;
} while (left < len);
} while(len);
dmaWaitCompletionRxTx(); // Wait DMA completion and stop it
dmaChannelWaitCompletionRxTx(); // Wait DMA completion and stop it
#endif
// restore speed if need
#ifdef LCD_SPI_RX_SPEED
@ -747,8 +710,7 @@ void ili9341_read_memory(int x, int y, int w, int h, uint16_t *out)
void ili9341_read_memory(int x, int y, int w, int h, uint16_t *out)
{
uint16_t len = w * h;
ili9341_setWindow(x, y, w, h);
send_command(ILI9341_MEMORY_READ, 0, NULL);
ili9341_setWindow(ILI9341_MEMORY_READ, x, y, w, h);
// Skip data from rx buffer
spi_DropRx();
// Set read speed (if need different)
@ -1314,6 +1276,7 @@ static uint16_t crc16(const uint8_t *ptr, uint16_t count) {
static inline uint8_t SD_ReadR1(uint32_t cnt) {
uint8_t r1;
// 8th bit R1 always zero, check it
spi_DropRx();
while(((r1=spi_RxByte())&0x80) && --cnt)
;
return r1;
@ -1324,6 +1287,7 @@ static inline bool SD_WaitDataToken(uint8_t token, uint32_t wait_time) {
uint8_t res;
uint32_t time = chVTGetSystemTimeX();
uint8_t count = 0;
spi_DropRx();
do{
if ((res = spi_RxByte()) == token)
return true;
@ -1337,6 +1301,7 @@ static inline bool SD_WaitDataToken(uint8_t token, uint32_t wait_time) {
static inline uint8_t SD_WaitDataAccept(uint32_t cnt) {
uint8_t res;
spi_DropRx();
while ((res = spi_RxByte()) == 0xFF && --cnt)
;
return res&0x1F;
@ -1347,6 +1312,7 @@ static uint8_t SD_WaitNotBusy(uint32_t wait_time) {
uint8_t res;
uint32_t time = chVTGetSystemTimeX();
uint8_t count = 0;
spi_DropRx();
do{
if ((res = spi_RxByte()) == 0xFF)
return res;
@ -1394,7 +1360,7 @@ static bool SD_TxDataBlock(const uint8_t *buff, uint8_t token) {
#endif
#ifdef __USE_SDCARD_DMA__
spi_DMATxBuffer((uint8_t*)buff, SD_SECTOR_SIZE);
spi_DMATxBuffer((uint8_t*)buff, SD_SECTOR_SIZE, true);
#else
spi_TxBuffer((uint8_t*)buff, SD_SECTOR_SIZE);
#endif
@ -1405,7 +1371,6 @@ static bool SD_TxDataBlock(const uint8_t *buff, uint8_t token) {
#else
spi_TxWord(0xFFFF);
#endif
spi_DropRx();
// Receive transmit data response token on next 10 bytes
resp = SD_WaitDataAccept(10);
if (resp != SD_TOKEN_DATA_ACCEPTED){
@ -1451,11 +1416,10 @@ static uint8_t SD_SendCmd(uint8_t cmd, uint32_t arg) {
buf[5] = crc;
#endif
spi_TxBuffer(buf, 6);
spi_DropRx();
// Skip a stuff byte when STOP_TRANSMISSION
//if (cmd == CMD12) SPI_RxByte();
// Receive response register r1
r1 = SD_ReadR1(10);
r1 = SD_ReadR1(100);
#if 1
if (r1&(SD_R1_NOT_R1|SD_R1_CRC_ERROR|SD_R1_ERASE_RESET|SD_R1_ERR_ERASE_CLR)){
DEBUG_PRINT(" SD_SendCmd err CMD%d, 0x%x, 0x%08x\r\n", (uint32_t)cmd-0x40, (uint32_t)r1, arg);
@ -1548,7 +1512,7 @@ DSTATUS disk_initialize(BYTE pdrv) {
if (cnt && SD_SendCmd(CMD58, 0) == 0)
{
DWORD ocr; spi_RxBuffer((uint8_t *)&ocr, 4);
DEBUG_PRINT(" CMD58 OCR = 0x%08X\r\n", _OCR(ocr));
DEBUG_PRINT(" CMD58 OCR = 0x%08x\r\n", _OCR(ocr));
// Check CCS bit, SDv2 (HC or SC)
type = (ocr & _OCR(SD_OCR_CAPACITY)) ? CT_SD2 | CT_BLOCK : CT_SD2;
}
@ -1627,10 +1591,10 @@ DRESULT disk_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count) {
#if DEBUG == 1
r_time+= chVTGetSystemTimeX();
if (count)
DEBUG_PRINT(" err READ_BLOCK %d 0x%08X\r\n", count, sector);
DEBUG_PRINT(" err READ_BLOCK %d 0x%08x\r\n", count, sector);
#if 0
else{
DEBUG_PRINT("Sector read 0x%08X %d \r\n", sector, cnt);
DEBUG_PRINT("Sector read 0x%08x %d \r\n", sector, cnt);
for (UINT j = 0; j < 32; j++){
for (UINT i = 0; i < 16; i++)
DEBUG_PRINT(" 0x%02x", buff[j*16 + i]);

15
spi.h

@ -78,6 +78,21 @@
#define SPI_READ_8BIT(spi) *(__IO uint8_t*)(&spi->DR)
#define SPI_READ_16BIT(spi) *(__IO uint16_t*)(&spi->DR)
//*****************************************************
// DMA channels macros
//*****************************************************
#define dmaChannelSetMemory(ch, addr) {(ch)->CMAR = (uint32_t)(addr);}
#define dmaChannelSetPeripheral(ch, addr) {(ch)->CPAR = (uint32_t)(addr);}
#define dmaChannelSetTransactionSize(ch, size) {(ch)->CNDTR= (uint32_t)(size);}
#define dmaChannelGetTransactionSize(ch) ((ch)->CNDTR)
#define dmaChannelSetMode(ch, mode) {(ch)->CCR = (uint32_t)(mode);}
#define dmaChannelEnable(ch) {(ch)->CCR |= STM32_DMA_CR_EN;}
#define dmaChannelDisable(ch) {(ch)->CCR &=~STM32_DMA_CR_EN;}
#define dmaChannelWaitCompletion(ch) {while ((ch)->CNDTR > 0); (ch)->CCR = 0;}
#define STM32_DMA_CR_BYTE (STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE)
#define STM32_DMA_CR_HWORD (STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD)
#ifdef TINYSA4
#define SPI_MODE_LCD 0x00
#define SPI_MODE_SD_CARD 0x01

Loading…
Cancel
Save

Powered by TurnKey Linux.