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