2018-08-09 03:02 AM
Hello,
my STM32F103C8T6 is being used for driving LCD display (ST7789, SPI2). Images are stored in the external FLASH memory (GD25Q16C, SPI1).
I am looking for an efficient way to transfer images from external FLASH to the LCD. In order to read data from the FLASH, I have to send start address, and then keep sending dummy bytes (so the chip increments address before sending new byte).
So far, I have managed to do the following procedure:
-tell LCD, that incoming bytes will be pixel colors,
-send start address to the External Flash chip
-send dummy byte, receive corresponding pixel color, send it to the LCD. Repeat 115200 times (1PAGE = 240x240x2bytes)
**LCD displays image**
I would like to improve this process, for example by using DMA in following way:
-tell LCD, that incoming bytes will be pixel colors,
-send start address to the External Flash chip
-enable SPI1 (flash) DMA transmit channel: send dummy byte 115200 times,
-enable SPI1 (flash) receive channel: receive data and put it into SPI2 (lcd) DMA Transmit register immediately
I am however unsure if this reasonable way, or if it is even possible to get data from SPI1 RX and put it into SPI2 TX by DMA
Solved! Go to Solution.
2018-08-09 01:13 PM
On a 'F1 this IMO may be possible.
> -enable SPI1 (flash) DMA transmit channel: send dummy byte 115200 times,
> -enable SPI1 (flash) receive channel: receive data and put it into SPI2 (lcd) DMA Transmit register immediately
No, this happens simultaneously. So you want
JW
2018-08-09 01:13 PM
On a 'F1 this IMO may be possible.
> -enable SPI1 (flash) DMA transmit channel: send dummy byte 115200 times,
> -enable SPI1 (flash) receive channel: receive data and put it into SPI2 (lcd) DMA Transmit register immediately
No, this happens simultaneously. So you want
JW
2018-08-13 04:56 AM
@Community member thanks for your reply!
I did what you said, althought I had some doubts regarding DMA peripheral-to-peripheral transfer for STM32, mainly because during DMA configuration I havent seen option for periph-to-periph direction. But I have just put SPI register into MemoryBaseAddr, and this worked beautifully (which had shocked me by the way):
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI1->DR;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&SPI2->DR;
Later on, I have added second DMA channel, that was used for sending dummy bytes to the external flash chip. All works very nice now ;)
If anyone has a similar problem, then this is my DMA configuration:
uint8_t volatile SPI_FLASH_dummyByte[1] = {0x00};
//==Configure DMA1 - Channel4== (SPI1.RX -> SPI2.TX)
/* External Flash sends data to our MCU -> this triggers DMA request
* DMA handler passes this data straight to the LCD_SPI transmit register */
DMA_DeInit(DMA1_Channel4);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&FLASH_SPIx->DR;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&LCD_SPIx->DR;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = 57600;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel4, &DMA_InitStructure);
//==Configure DMA1 - Channel5== (Memory -> SPI1.TX)
/* MCU sends dummy bytes to the External Flash, so the
* External Flash sends us data, increments address
* and repeats this DMA_BufferSize times */
DMA_DeInit(DMA1_Channel5);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&FLASH_SPIx->DR;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)SPI_FLASH_dummyByte;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = 57600;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel5, &DMA_InitStructure);
/* Enable SPI_MASTER DMA Rx request for the EXTERNAL FLASH SPI */
SPI_I2S_DMACmd(FLASH_SPIx, SPI_I2S_DMAReq_Rx, ENABLE);
/* Enable SPI_MASTER DMA Tx request for the EXTERNAL FLASH SPI */
SPI_I2S_DMACmd(FLASH_SPIx, SPI_I2S_DMAReq_Tx, ENABLE);
and this code triggers communication between external flash and my LCD screen (written in C++)
display->startDrawing();
display->setAddress(0, 0, LCD_W - 1, LCD_H - 1); //LCD will start filling screen within specified area
Ext_flash::select(); //Begin communication with flash chip
Ext_flash::spi_sendrecv(0x03); //READ_DATA command
Ext_flash::spi_sendrecv( ((0x00 >> 16) & 0xFF ) ); //Send 24-bit address
Ext_flash::spi_sendrecv( ((0x00 >> 8) & 0xFF ) );
Ext_flash::spi_sendrecv( ((0x00) & 0xFF ) );
/*** Configure DMA1_Channel4 so it sends 57600 bytes from MCU to FLASH */
/* Disable DMA1_ChannelX in order to set new DataCounter */
DMA_Cmd(DMA1_Channel4, DISABLE);
DMA_ClearFlag(DMA1_FLAG_TC4);
DMA_SetCurrDataCounter(DMA1_Channel4, 57600);
/*** Configure DMA1_Channel5 so it receives 57600 bytes from FLASH (SPI2.RX) and immediately sends it to the LCD (SPI1.TX) */
DMA_Cmd(DMA1_Channel5, DISABLE);
DMA_ClearFlag(DMA1_FLAG_TC5);
DMA_SetCurrDataCounter(DMA1_Channel5, 57600);
/* Enable DMA channels */
DMA_Cmd(DMA1_Channel5, ENABLE);
/* Enable DMA channels */
DMA_Cmd(DMA1_Channel4, ENABLE);
/* Transfer complete */
while(!DMA_GetFlagStatus(DMA1_FLAG_TC5));
/* Transfer complete */
while(!DMA_GetFlagStatus(DMA1_FLAG_TC4));
Ext_flash::deselect();
display->endDrawing();