One of my key customer is using DSPI1 to read extern flash, now they meet one problem, they want to read flash content via DMA,but SPI1 has only one DMA request source number for Transmit or Receive, so they send the flash command manually(without DMA), then enable DMA and set CONT_SCKE to generate continuous SCK signal to read flash,DMA can't get any data, the buffer is empty,We use Oscilloscope to observe wave, we can find the data from Flash;If they sent the dummy data( CONT_SCKE is clear) manually and received data using DMA, it is OK. I don't know if there is any error on SPI setting and DMA setting, or K21 can't support the usage? Thanks
int STDCALL SFlashHwInit(VOID)
{
//SPI配置结构体定义
SPI_InitTypeDef SPI_InitStructure = SPI_INIT_DEFAULT;
//时钟初始化
SIM_SCGxClockEnable(SCG6, SFLASH_SPI_CLK_MASK);
SIM_SCGxClockEnable(SCG5, SFLASH_GPIO_CLK_MASK);
//SPI IO口设置
GPIO_Set(SFLASH_SCK_GPIO, SFLASH_SCK_PIN, GPIO_Direction_OUT, SFLASH_SCK_MUX, GPIO_SlewRate_Fast | GPIO_DriveStrength_High);
GPIO_Set(SFLASH_MOSI_GPIO, SFLASH_MOSI_PIN, GPIO_Direction_OUT, SFLASH_MOSI_MUX, GPIO_SlewRate_Fast);
GPIO_Set(SFLASH_CS_GPIO, SFLASH_CS_PIN, GPIO_Direction_OUT, SFLASH_CS_MUX, GPIO_SlewRate_Fast);
GPIO_Set(SFLASH_MISO_GPIO, SFLASH_MISO_PIN, GPIO_Direction_IN, SFLASH_MISO_MUX, GPIO_SlewRate_Fast);
GPIO_Set(GPIOA, GPIO_Pin_13, GPIO_Direction_OUT, GPIO_MUX_ALT1, GPIO_SlewRate_Fast);
GPIO_SetBits(SFLASH_CS_GPIO, SFLASH_CS_PIN);
#ifdef SFLASH_WP_PIN
GPIO_Set(SFLASH_WP_GPIO, SFLASH_WP_PIN, GPIO_Direction_OUT, SFLASH_WP_MUX, GPIO_SlewRate_Fast);
#endif
//spi, clock is 48/2 = 24 MHz
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_BaudrateScaler = SPI_BAUDRATE_SCALER_4;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_PSCState = SPI_PSC0State_High;
SPI_InitStructure.SPI_BaudratePreScaler = SPI_BAUDRATE_PRESCALER_2;
SPI_Init(SFLASH_SPI, &SPI_InitStructure);
SPI1DMAConfig(szSPIBuf, SPI_DMA_BUF_LEN);
SPI_Cmd(SFLASH_SPI, ENABLE);
#ifdef SFLASH_WP_PIN
//WP设为上拉输入,由硬件上拉,此处也做上拉处理
GPIO_SetBits(SFLASH_WP_GPIO, SFLASH_WP_PIN);
#endif
//DMA_ReqCmd(DMA_CH3, ENABLE);
return SUCCESS;
}
// void _SFlashWaitData(void)
// {
// while ((SFLASH_SPI->SR & SPI_FLAG_RFDF) == RESET)
// {
// ;
// }
// SFLASH_SPI->SR |= SPI_FLAG_RFDF;
// }
INT SPI1DMAConfig(P_U8 DMABuf, UINT DMABufLen)
{
DMA_InitTypeDef DMA_InitStructure;
// 打开DMA时钟
SIM_ModuleClockCmd(DMA_CLK, ENABLE);
SIM_ModuleClockCmd(DMAMUX_CLK, ENABLE);
SIM_SCGC6 |= SIM_SCGC6_DMAMUX_MASK;
DMA_InitStructure.DMA_Channelx = DMA_CH3;
DMA_InitStructure.DMA_Source_Req = 18;//SPI1_REV_DMAREQ;
DMA_InitStructure.DMA_Trigger = DMA_Trigger_Disable;
DMA_InitStructure.DMA_Major_Iteration_Count = DMABufLen;
DMA_InitStructure.DMA_Minor_loop_Length = 1;
DMA_InitStructure.DMA_Source_Addr = (U32)(&(SPI_POPR_REG(SPI1)));
DMA_InitStructure.DMA_Source_Size = DMA_SRC_8BIT;
DMA_InitStructure.DMA_Source_Addr_inc = 0;
DMA_InitStructure.DMA_Source_Adj_Addr = 0;
DMA_InitStructure.DMA_Dest_Addr = (U32)DMABuf;
DMA_InitStructure.DMA_Dest_Size = DMA_DST_8BIT;
DMA_InitStructure.DMA_Dest_Addr_inc = 1;
DMA_InitStructure.DMA_Dest_Adj_Addr = (U32)(-DMABufLen);
DMA_InitStructure.DMA_AutoClose = DMA_AutoClose_NOT;
DMA_Init(&DMA_InitStructure);
//DMA_ReqCmd(DMA_CH3, ENABLE);
//USART_DMARxCmd(pUartBase, ENABLE);
SPI_RSER_REG(SPI1_BASE_PTR) |= SPI_RSER_RFDF_RE_MASK | SPI_RSER_RFDF_DIRS_MASK;// | SPI_RSER_TFFF_RE_MASK | SPI_RSER_TFFF_DIRS_MASK;
return SUCCESS;
}
INT STDCALL SFlashDrvReadBytes(UINT uAddr, PVOID pBuf, INT uRdSize)
{
UINT uRdNum;
UINT uRdRemainNum;
UINT uSFlashAddr;
PBYTE pRdBuf = pBuf;
//U32 u32DummyData = SFCMD_DUMMY;
uRdNum = 0;
uSFlashAddr = uAddr - SFLASH_ADDR_BEGIN;
uRdNum = uRdSize>>2UL;
uRdRemainNum = uRdSize & 0x3;
//ENTER_HW_IRQL_PRTCT
//DMA_ReqCmd(DISABLE);
_SFlashCSLow();
_SFlashSendByte(SFCMD_READ_50MHZ);
//发送地址,24位地址,发送3次,STM32F10X的SPI 8位数据帧格式发送的是低8位数据
_SFlashSendByte((uSFlashAddr & 0xFF0000)>>16UL);
_SFlashSendByte((uSFlashAddr & 0xFF00)>>8UL);
_SFlashSendByte(uSFlashAddr & 0xFF);
//接收数据
ClearRecvData();
//设置数据长度,长度每次递减。也可以称为 当前主循环计数器 current major loop count
DMA_BASE_PTR->TCD[DMA_CH3].CITER_ELINKNO = DMA_CITER_ELINKNO_CITER(uRdSize);
//起始循环计数器,当主循环计数器为零的时候,将装载起始循环计数器的值
DMA_BASE_PTR->TCD[DMA_CH3].BITER_ELINKNO = DMA_CITER_ELINKNO_CITER(uRdSize);
DMA_BASE_PTR->TCD[DMA_CH3].DLAST_SGA = (U32)(-uRdSize);
DMA_ReqCmd(DMA_CH3, ENABLE);
//u32DummyData |= (SPI_PUSHR_REG(SFLASH_SPI) & 0xffff0000);
#define _DMA_SPI_
#ifndef _DMA_SPI_
for(; uRdNum != 0; uRdNum--)
{
//((PBYTE)pBuf)[uRdNum++] = _SFlashSendByte(SFCMD_DUMMY);
//
_SFlashSendData(SFLASH_SPI, SPI_PUSHR_REG(SFLASH_SPI));
_SFlashWaitSend();
//*pRdBuf++ = _SFlashReciveData(SFLASH_SPI);
_SFlashSendData(SFLASH_SPI, SPI_PUSHR_REG(SFLASH_SPI));
_SFlashWaitSend();
//*pRdBuf++ = _SFlashReciveData(SFLASH_SPI);
_SFlashSendData(SFLASH_SPI, SPI_PUSHR_REG(SFLASH_SPI));
_SFlashWaitSend();
//*pRdBuf++ = _SFlashReciveData(SFLASH_SPI);
_SFlashSendData(SFLASH_SPI, SPI_PUSHR_REG(SFLASH_SPI));
_SFlashWaitSend();
//*pRdBuf++ = _SFlashReciveData(SFLASH_SPI);
}
for(; uRdRemainNum != 0; uRdRemainNum--)
{
_SFlashSendData(SFLASH_SPI, SPI_PUSHR_REG(SFLASH_SPI));
_SFlashWaitSend();
//*pRdBuf++ = _SFlashReciveData(SFLASH_SPI);
}
extern U8 szSPIBuf[];
memcpy(pRdBuf, szSPIBuf, uRdSize);
// SPI_MCR_REG(SPI1) |= SPI_MCR_CONT_SCKE_MASK;
//for(uRdRemainNum = uRdSize; uRdRemainNum > 0; uRdRemainNum--)
//{
// //while((SFLASH_SPI->SR & SPI_FLAG_TCF) == 0)
// //{
// //}
// //SFLASH_SPI->SR |= SPI_FLAG_TCF;
// *pRdBuf++ = _SFlashReciveData(SFLASH_SPI);
//}
// SPI_MCR_REG(SPI1) &= ~SPI_MCR_CONT_SCKE_MASK;
#else
SPI_MCR_REG(SPI1) |= SPI_MCR_CONT_SCKE_MASK;
while((DMA_TCD3_CSR & 0x80) == 0);
SPI_MCR_REG(SPI1) &= ~SPI_MCR_CONT_SCKE_MASK;
extern U8 szSPIBuf[];
//uRdSize = (uRdSize >= DMA_CITER_ELINKNO_CITER(DMA_BASE_PTR->TCD[DMA_CH3].CITER_ELINKNO)) ? DMA_CITER_ELINKNO_CITER(DMA_BASE_PTR->TCD[DMA_CH3].CITER_ELINKNO) : uRdSize;
memcpy(pRdBuf, szSPIBuf, uRdSize);
DMA_TCD3_CSR |= 0x10;
#endif
//拉高SFlash的CS
_SFlashCSHigh();
DMA_ReqCmd(DMA_CH3, DISABLE);
//EXIT_HW_IRQL_PRTCT
return uRdSize;
}
For picture:
Green: SCK
Blue: MISO
Purple: MISO
Yellow: CS
Hi Yanrong Fu,
I'd like to suggest that you can refer to a practical experiment document about the SPI integrate with DMA throught the link as below.
If you have any further questions about it, please feel free to contact with me.
使用DMA降低SPI通信过程中内核负荷 Reduce core work load with DMA Module during SPI communication
Have a great day,
Ping
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hi Ping,
Thanks you for your infromation.But my problem is difference with the ref., my customer use DSPI1, DSPI1 has only one DMA request source number for Transmit or Receive, I can't use one DMA channel for transmitting and another DMA channel for receiving.
Best Regards,
Fred Fu
Hi Yanrong Fu,
As you mentioned at first, the MCU could received the data from external flash correctly through the DMA while the SPI was sending the dummy data.
Follow to this method, did it not work with K21?
Have a great day,
Ping
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hi Ping,
It is now being used in ways, because DSPI can't use DMA to transmit when DAM for receiving, the efficiency is low. Now they want to improve the efficiency, they enable CONT_SCKE to generate clk for flash(you can see the source code),then DMA for receiving, but DMA can't get any data, I want to know if K21F can support the way. Thanks.
Best Regards,
Fred Fu