- 最近需要用华大的hc32l136的硬件SPI+DMA传输,瞎写很久没调好,看参考手册,瞎碰一天搞通了。。。
- 先说下我之前犯的错误,也是最宝贵的经验,供参考
- 没多看参考手册直接写(即使有点烂仍然提供了最高的参考价值。。。),重点看
SPI
和DMAC
章节 - 错误使用了
软件触发传输
,测到的现象是前两个字节可以正确发送,后面的无论是发送数量和数据都对不上了,误以为软件触发可用,自己的配置有问题,实际测试软件触发和规格书讲的一样,是不可用的或者说是不可靠的
- 再说下正确的使用方式,文末会粘上测试代码
- 关键点就一个,触发方式
不要选DmaSWTrig软件触发
(至于最后实例能用的这个,从软件的角度看还是软件触发,但官方的角度似乎不认为这是软件触发,或许是软件触发SPI硬件再触发DMA所以叫硬件触发?不管也罢,,,)
- 语文课兴许没及格,下面是参考手册的一些相关描述,没看明白:
- 先讲SPI支持软硬件访问
2.再讲只支持硬件块传输模式,且SPI和系统时钟不同频时不支持硬件触发(官方对软件/硬件触发的解释不是很到位,至少和我理解的不太一样)
- 但是spi时钟和系统时钟必然是不同频的,那硬件触发到底能不能用呢?
- 再看,所谓的软件/硬件DMA传输模式就是软件/硬件请求方式不同,似乎哪个也不支持了。。。软硬件触发和软硬件传输似乎没有关系?
- 最后,还是实践出真知。。。
- 测试程序参考,每200ms用SPI+DMA发送24个字节:
#define SPI_HANDLE M0P_SPI1
#define DMA_HANDLE DmaCh1
uint8_t data_tx_test[24] =
{
0x11,0x22,0x23,0x44,0x55,0x66,0x77,0x88,
0x11,0x22,0x23,0x44,0x55,0x66,0x77,0x88,
0x11,0x22,0x23,0x44,0x55,0x66,0x77,0x88,
};
static void App_GpioInit(void)
{
stc_gpio_cfg_t stcPortCfg;
DDL_ZERO_STRUCT(stcPortCfg);
Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE);
stcPortCfg.enDrv = GpioDrvH;
stcPortCfg.enDir = GpioDirOut;
Gpio_Init(LCD_BK_PORT, LCD_BK_PIN, &stcPortCfg);
Gpio_Init(LCD_CS_PORT, LCD_CS_PIN, &stcPortCfg);
Gpio_SetAfMode(LCD_CS_PORT, LCD_CS_PIN,GpioAf1);
Gpio_Init(LCD_RESET_PORT, LCD_RESET_PIN, &stcPortCfg);
Gpio_Init(LCD_WR_PORT, LCD_WR_PIN, &stcPortCfg);
Gpio_Init(LCD_SCK_PORT, LCD_SCK_PIN, &stcPortCfg);
Gpio_SetAfMode(LCD_SCK_PORT, LCD_SCK_PIN,GpioAf1);
Gpio_Init(LCD_SDA_PORT, LCD_SDA_PIN, &stcPortCfg);
Gpio_SetAfMode(LCD_SDA_PORT, LCD_SDA_PIN,GpioAf1);
}
static void App_SPIInit(void)
{
stc_spi_cfg_t SpiInitStruct;
Sysctrl_SetPeripheralGate(SysctrlPeripheralSpi1,TRUE);
SpiInitStruct.enSpiMode = SpiMskMaster;
SpiInitStruct.enPclkDiv = SpiClkMskDiv2;
SpiInitStruct.enCPOL = SpiMskcpolhigh;
SpiInitStruct.enCPHA = SpiMskCphasecond;
Spi_Init(SPI_HANDLE, &SpiInitStruct);
Spi_FuncEnable(SPI_HANDLE,SpiMskDmaTxEn);
}
static void App_DmaCfg(void)
{
stc_dma_cfg_t stcDmaCfg;
Sysctrl_SetPeripheralGate(SysctrlPeripheralDma,TRUE);
DDL_ZERO_STRUCT(stcDmaCfg);
stcDmaCfg.enMode = DmaMskBlock;
stcDmaCfg.u16BlockSize = 1;
stcDmaCfg.u16TransferCnt = 24;
stcDmaCfg.enTransferWidth = DmaMsk8Bit;
stcDmaCfg.enSrcAddrMode = DmaMskSrcAddrInc;
stcDmaCfg.enDstAddrMode = DmaMskDstAddrFix;
stcDmaCfg.enDestAddrReloadCtl = DmaMskDstAddrReloadEnable;
stcDmaCfg.enSrcAddrReloadCtl = DmaMskSrcAddrReloadEnable;
stcDmaCfg.enSrcBcTcReloadCtl = DmaMskBcTcReloadEnable;
stcDmaCfg.u32SrcAddress = (uint32_t)&data_tx_test[0];
stcDmaCfg.u32DstAddress = (uint32_t)&(M0P_SPI1->DATA);
stcDmaCfg.enRequestNum = DmaSPI1TXTrig;
stcDmaCfg.enTransferMode = DmaMskOneTransfer;
stcDmaCfg.enPriority = DmaMskPriorityFix;
Dma_InitChannel(DMA_HANDLE,&stcDmaCfg);
Dma_Enable();
Dma_EnableChannel(DMA_HANDLE);
}
void dma_test(void)
{
en_dma_stat_t ste;
while(1)
{
delay1ms(200);
M0P_SPI1->SSN = FALSE;
Dma_EnableChannel(DMA_HANDLE);
ste = Dma_GetStat(DMA_HANDLE);
while(ste != DmaTransferComplete)
{
ste = Dma_GetStat(DMA_HANDLE);
}
M0P_SPI1->SSN = TRUE;
}
}
void demo(void)
{
App_GpioInit();
App_DmaCfg();
App_SPIInit();
dma_test();
}
- 实测SPI主机发送ok: