五、关于zephyr上使用spi通信时(如使用dma+回调)需要的配置
📅 2026/7/3 7:00:01
👁️ 阅读次数
📝 编程学习
首先app.overlay的配置
使用dma+回调方式
&dma1{status="okay";};&dmamux1{status="okay";};&spi2{/* 使用 PLL1_Q 作为 SPI2 时钟源 */pinctrl-0=<&spi2_nss_pb12&spi2_sck_pb13&spi2_miso_pb14&spi2_mosi_pb15>;pinctrl-names="default";status="okay";dmas=<&dmamux1040(STM32_DMA_PERIPH_TX|STM32_DMA_PRIORITY_HIGH)>,<&dmamux1139(STM32_DMA_PERIPH_RX|STM32_DMA_PRIORITY_HIGH)>;dma-names="tx","rx";};在pro.conf中添加
CONFIG_NOCACHE_MEMORY=y CONFIG_SPI_ASYNC=y CONFIG_SPI=y CONFIG_SPI_STM32=y CONFIG_SPI_STM32_DMA=y CONFIG_SPI_STM32_INTERRUPT=ymain.c测试
#definePACKET_SIZE64#defineTEST_COUNT10/* 测试数据 */staticconstuint8_ttx_pattern[PACKET_SIZE]={0xAA,0x55,0x12,0x34,0xDE,0xAD,0xBE,0xEF,0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF,0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF,0xFE,0xDC,0xBA,0x98,0x76,0x54,0x32,0x10,0xA5,0x5A,0xA5,0x5A,0xA5,0x5A,0xA5,0x5A,0xFF,0xEE,0xDD,0xCC,0xBB,0xAA,0x99,0x88,0x77,0x66,0x55,0x44,0x33,0x22,0x11,0x00};__nocachestaticuint8_ttx_buffer[PACKET_SIZE];__nocachestaticuint8_trx_buffer[PACKET_SIZE];/* 同步信号量(用于等待异步回调) */staticK_SEM_DEFINE(spi_sync_sem,0,1);/* 传输结果(回调中写入) */staticintspi_transfer_result;/* SPI 配置 */staticstructspi_configspi2_cfg={.frequency=16000000,.operation=SPI_OP_MODE_MASTER|SPI_WORD_SET(8)|SPI_TRANSFER_MSB,.slave=0,};/* ================================================================ * 异步传输完成回调 * 在中断上下文中调用,仅做标记+释放信号量,不能做耗时操作 * ================================================================ */staticvoidspi_transfer_done(conststructdevice*dev,intresult,void*user_data){spi_transfer_result=result;k_sem_give(&spi_sync_sem);}/* ================================================================ * 单次异步收发(封装:提交 + 等待回调) * 返回 0 成功,负值为错误码 * ================================================================ */staticintspi_transceive_async_once(conststructdevice*dev,conststructspi_config*cfg,constuint8_t*tx_data,size_ttx_len,uint8_t*rx_data,size_trx_len,int32_ttimeout_ms){/* 构建 TX buf */structspi_buftx_buf={.buf=(void*)tx_data,.len=tx_len,};structspi_buf_settx_set={.buffers=&tx_buf,.count=1,};/* 构建 RX buf */structspi_bufrx_buf={.buf=rx_data,.len=rx_len,};structspi_buf_setrx_set={.buffers=&rx_buf,.count=1,};/* 提交异步传输 */intret=spi_transceive_cb(dev,cfg,&tx_set,&rx_set,spi_transfer_done,NULL);if(ret<0){printk("spi_transceive_cb submit failed: %d\n",ret);returnret;}/* 等待回调唤醒 */ret=k_sem_take(&spi_sync_sem,K_MSEC(timeout_ms));if(ret!=0){printk("SPI transfer timeout! (%d)\n",ret);return-ETIMEDOUT;}/* 检查传输结果 */if(spi_transfer_result<0){printk("SPI transfer error: %d\n",spi_transfer_result);returnspi_transfer_result;}return0;}voidmy_thread(void*arg1,void*arg2,void*arg3){intpass=0,fail=0;k_msleep(500);printk("\n");printk("============================================\n");printk(" SPI2 + DMA Async Loopback Test\n");printk(" Connect: PB14(MISO) <-> PB15(MOSI)\n");printk(" Packet size: %d bytes\n",PACKET_SIZE);printk("============================================\n\n");conststructdevice*spi2=DEVICE_DT_GET(DT_NODELABEL(spi2));if(!device_is_ready(spi2)){printk("ERROR: SPI2 device not ready!\n");while(1){k_sleep(K_FOREVER);}}printk("SPI2 device ready\n");printk("tx_buffer addr: %p\n",tx_buffer);printk("rx_buffer addr: %p\n",rx_buffer);memcpy(tx_buffer,tx_pattern,PACKET_SIZE);/* 循环测试 */for(inti=0;i<TEST_COUNT;i++){memset(rx_buffer,0,PACKET_SIZE);intret=spi_transceive_async_once(spi2,&spi2_cfg,tx_buffer,PACKET_SIZE,rx_buffer,PACKET_SIZE,11000);if(ret<0){printk("[%2d] FAIL: error %d\n",i,ret);fail++;continue;}if(memcmp(tx_buffer,rx_buffer,PACKET_SIZE)==0){printk("[%2d] PASS\n",i);pass++;}else{printk("[%2d] FAIL: data mismatch\n",i);printk(" byte[0]: tx=0x%02X rx=0x%02X\n",tx_buffer[0],rx_buffer[0]);fail++;}k_msleep(100);}printk("\n============================================\n");printk(" Result: PASS=%d FAIL=%d (Total=%d)\n",pass,fail,TEST_COUNT);printk("============================================\n");while(1){k_msleep(1000);}}使用正常的收发方式(即收发一体),上面配置中取消dma相关即可。
main.c
#definePACKET_SIZE8staticconstuint8_ttx_pattern[PACKET_SIZE]={0xAA,0x55,0x12,0x34,0xDE,0xAD,0xBE,0xEF};staticuint8_trx_buffer[PACKET_SIZE];staticstructspi_configspi2_cfg_fast={.frequency=16000000,.operation=SPI_TRANSFER_LSB|SPI_WORD_SET(8)|SPI_TRANSFER_MSB|SPI_MODE_CPOL|SPI_MODE_CPHA,.slave=0,};voidmy_thread(void*arg1,void*arg2,void*arg3){intpass=0,fail=0;printk("=== SPI2 Interrupt Loopback Test ===\n");printk("Connect PB14(MISO) <-> PB15(MOSI)\n\n");conststructdevice*spi2=DEVICE_DT_GET(DT_NODELABEL(spi2));if(!device_is_ready(spi2)){printk("SPI2 not ready!\n");}printk("SPI2 ready\n\n");for(inti=0;i<10;i++){memset(rx_buffer,0,PACKET_SIZE);structspi_buftx={.buf=(void*)tx_pattern,.len=PACKET_SIZE};structspi_bufrx={.buf=rx_buffer,.len=PACKET_SIZE};structspi_buf_settx_set={.buffers=&tx,.count=1};structspi_buf_setrx_set={.buffers=&rx,.count=1};intret=spi_transceive(spi2,&spi2_cfg_fast,&tx_set,&rx_set);if(ret<0){printk("Iter %d: fail\n",i);fail++;continue;}if(memcmp(tx_pattern,rx_buffer,PACKET_SIZE)==0){printk("Iter %d: OK\n",i);pass++;}else{printk("Iter %d: mismatch\n",i);fail++;}}printk("\n=== Result: Pass=%d Fail=%d ===\n",pass,fail);while(1){k_msleep(1000);}}
编程学习
技术分享
实战经验