- 最近需要用华大的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 DmaCh1uint8_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();
}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:
