Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
DIY综合交流区
关于SPI驱动的建议
发布于 2012-09-26 07:47:53 浏览:6504
订阅该版
使用了SPI驱动,芯片是STM32F407VE,修改来自stm32f20x_40x_spi.c,有以下几点可能需要修改一下: 1.stm32_spi_register只在SPI2的时候有赋值 stm32_spi->SPI = SPI2;其他SPI1,SPI3都没有,导致使用SPI1,SPI3时,出现错误,如下代码 ```rt_err_t stm32_spi_register(SPI_TypeDef * SPI, struct stm32_spi_bus * stm32_spi, const char * spi_bus_name) { if(SPI == SPI1) { stm32_spi->SPI = SPI1;//lzm 20120924 #ifdef SPI_USE_DMA RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); /* DMA2_Stream0 DMA_Channel_3 : SPI1_RX */ /* DMA2_Stream2 DMA_Channel_3 : SPI1_RX */ stm32_spi->DMA_Stream_RX = DMA2_Stream0; stm32_spi->DMA_Channel_RX = DMA_Channel_3; stm32_spi->DMA_Channel_RX_FLAG_TC = DMA_FLAG_TCIF0; /* DMA2_Stream3 DMA_Channel_3 : SPI1_TX */ /* DMA2_Stream5 DMA_Channel_3 : SPI1_TX */ stm32_spi->DMA_Stream_TX = DMA2_Stream3; stm32_spi->DMA_Channel_TX = DMA_Channel_3; stm32_spi->DMA_Channel_TX_FLAG_TC = DMA_FLAG_TCIF3; #endif RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); } else if(SPI == SPI2) { stm32_spi->SPI = SPI2; #ifdef SPI_USE_DMA RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); /* DMA1_Stream3 DMA_Channel_0 : SPI2_RX */ stm32_spi->DMA_Stream_RX = DMA1_Stream3; stm32_spi->DMA_Channel_RX = DMA_Channel_0; stm32_spi->DMA_Channel_RX_FLAG_TC = DMA_FLAG_TCIF3; /* DMA1_Stream4 DMA_Channel_0 : SPI2_TX */ stm32_spi->DMA_Stream_TX = DMA1_Stream4; stm32_spi->DMA_Channel_TX = DMA_Channel_0; stm32_spi->DMA_Channel_TX_FLAG_TC = DMA_FLAG_TCIF4; #endif RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE); } else if(SPI == SPI3) { stm32_spi->SPI = SPI3;//lzm 20120924 #ifdef SPI_USE_DMA RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); /* DMA1_Stream2 DMA_Channel_0 : SPI3_RX */ stm32_spi->DMA_Stream_RX = DMA1_Stream2; stm32_spi->DMA_Channel_RX = DMA_Channel_0; stm32_spi->DMA_Channel_RX_FLAG_TC = DMA_FLAG_TCIF2; /* DMA1_Stream5 DMA_Channel_0 : SPI3_TX */ stm32_spi->DMA_Stream_TX = DMA1_Stream5; stm32_spi->DMA_Channel_TX = DMA_Channel_0; stm32_spi->DMA_Channel_TX_FLAG_TC = DMA_FLAG_TCIF5; #endif RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE); } else { return RT_ENOSYS; } return rt_spi_bus_register(&stm32_spi->parent, spi_bus_name, &stm32_spi_ops); }```
查看更多
7
个回答
默认排序
按发布时间排序
lzm0117
2012-09-26
这家伙很懒,什么也没写!
2.关于数据位宽与DMA的关系,原文件中好像只有8位数据位才能使用DMA传输,实际16位也可以DMA传输,我代码改动如下: ``` #ifdef SPI_USE_DMA static uint16_t dummy = 0xFF; static void DMA_RxConfiguration(struct stm32_spi_bus * stm32_spi_bus, const void * send_addr, void * recv_addr, rt_size_t size) { DMA_InitTypeDef DMA_InitStructure; /* Reset DMA Stream registers (for debug purpose) */ DMA_DeInit(stm32_spi_bus->DMA_Stream_RX); DMA_DeInit(stm32_spi_bus->DMA_Stream_TX); /* Check if the DMA Stream is disabled before enabling it. Note that this step is useful when the same Stream is used multiple times: enabled, then disabled then re-enabled... In this case, the DMA Stream disable will be effective only at the end of the ongoing data transfer and it will not be possible to re-configure it before making sure that the Enable bit has been cleared by hardware. If the Stream is used only once, this step might be bypassed. */ while (DMA_GetCmdStatus(stm32_spi_bus->DMA_Stream_RX) != DISABLE); while (DMA_GetCmdStatus(stm32_spi_bus->DMA_Stream_TX) != DISABLE); /* Configure DMA_RX Stream */ DMA_Cmd(stm32_spi_bus->DMA_Stream_RX, DISABLE); DMA_InitStructure.DMA_Channel = stm32_spi_bus->DMA_Channel_RX; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(stm32_spi_bus->SPI->DR)); DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_InitStructure.DMA_BufferSize = (uint32_t)size; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_PeripheralDataSize = DMA_MemoryDataSize_HalfWord;//LZM 20120925 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//LZM 20120925 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; if(recv_addr != RT_NULL) { DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) recv_addr; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; } else { DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) (&dummy); DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; } DMA_Init(stm32_spi_bus->DMA_Stream_RX, &DMA_InitStructure); DMA_Cmd(stm32_spi_bus->DMA_Stream_RX, ENABLE); /* Configure DMA_TX Stream */ DMA_Cmd(stm32_spi_bus->DMA_Stream_TX, DISABLE); DMA_InitStructure.DMA_Channel = stm32_spi_bus->DMA_Channel_TX; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(stm32_spi_bus->SPI->DR)); DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; DMA_InitStructure.DMA_BufferSize = (uint32_t)size; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_PeripheralDataSize = DMA_MemoryDataSize_HalfWord;//LZM 20120925 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//LZM 20120925 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; if(send_addr != RT_NULL) { DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)send_addr; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; } else { dummy = 0xFF; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)(&dummy);; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; } DMA_Init(stm32_spi_bus->DMA_Stream_TX, &DMA_InitStructure); DMA_Cmd(stm32_spi_bus->DMA_Stream_TX, ENABLE); } #endif static rt_uint32_t xfer(struct rt_spi_device* device, struct rt_spi_message* message) { struct stm32_spi_bus * stm32_spi_bus = (struct stm32_spi_bus *)device->bus; struct rt_spi_configuration * config = &device->config; SPI_TypeDef * SPI = stm32_spi_bus->SPI; struct stm32_spi_cs * stm32_spi_cs = device->parent.user_data; rt_uint32_t size = message->length; /* take CS */ if(message->cs_take) { GPIO_ResetBits(stm32_spi_cs->GPIOx, stm32_spi_cs->GPIO_Pin); } #ifdef SPI_USE_DMA if(message->length > 32) { //if(config->data_width <= 8)//LZM 20120925 { DMA_RxConfiguration(stm32_spi_bus, message->send_buf, message->recv_buf, message->length); // SPI_I2S_ClearFlag(SPI, SPI_I2S_FLAG_RXNE); SPI_I2S_DMACmd(SPI, SPI_I2S_DMAReq_Tx | SPI_I2S_DMAReq_Rx, ENABLE); while (DMA_GetFlagStatus(stm32_spi_bus->DMA_Stream_RX, stm32_spi_bus->DMA_Channel_RX_FLAG_TC) == RESET || DMA_GetFlagStatus(stm32_spi_bus->DMA_Stream_TX, stm32_spi_bus->DMA_Channel_TX_FLAG_TC) == RESET); SPI_I2S_DMACmd(SPI, SPI_I2S_DMAReq_Tx | SPI_I2S_DMAReq_Rx, DISABLE); } } else #endif { if(config->data_width <= 8) { const rt_uint8_t * send_ptr = message->send_buf; rt_uint8_t * recv_ptr = message->recv_buf; while(size--) { rt_uint8_t data = 0xFF; if(send_ptr != RT_NULL) { data = *send_ptr++; } //Wait until the transmit buffer is empty while (SPI_I2S_GetFlagStatus(SPI, SPI_I2S_FLAG_TXE) == RESET); // Send the byte SPI_I2S_SendData(SPI, data); //Wait until a data is received while (SPI_I2S_GetFlagStatus(SPI, SPI_I2S_FLAG_RXNE) == RESET); // Get the received data data = SPI_I2S_ReceiveData(SPI); if(recv_ptr != RT_NULL) { *recv_ptr++ = data; } } } else if(config->data_width <= 16) { const rt_uint16_t * send_ptr = message->send_buf; rt_uint16_t * recv_ptr = message->recv_buf; while(size--) { rt_uint16_t data = 0xFF; if(send_ptr != RT_NULL) { data = *send_ptr++; } //Wait until the transmit buffer is empty while (SPI_I2S_GetFlagStatus(SPI, SPI_I2S_FLAG_TXE) == RESET); // Send the byte SPI_I2S_SendData(SPI, data); //Wait until a data is received while (SPI_I2S_GetFlagStatus(SPI, SPI_I2S_FLAG_RXNE) == RESET); // Get the received data data = SPI_I2S_ReceiveData(SPI); if(recv_ptr != RT_NULL) { *recv_ptr++ = data; } } } } /* release CS */ if(message->cs_release) { GPIO_SetBits(stm32_spi_cs->GPIOx, stm32_spi_cs->GPIO_Pin); } return message->length; }; ``` 实际证明,对SPI WIFI 传输,使用16位DMA传输,数据可以正常传输,但在 ``` static void DMA_RxConfiguration(struct stm32_spi_bus * stm32_spi_bus, const void * send_addr, void * recv_addr, rt_size_t size) ``` 函数中,如何能把数据位宽也传递过来?增加一个参数?
lzm0117
2012-09-26
这家伙很懒,什么也没写!
3.DMA传输等待问题,目前的处理是通过轮询DMA的状态位来实现,这样虽然比SPI单个传输快,但线程时间都浪费在等待上,无法体现DMA的优势,如果能采用DMA中断,中断中rt_sem_release(),在触发完DMA传输,主线程rt_sem_take(),这样是否可以更好地提升处理能力?
xiao苦
2012-09-26
这家伙很懒,什么也没写!
使用SPI DMA+Sem搭配方式速度快,而且能省资源,我测试过, 因为我的驱动就是这么编的,但是要注意,写入的时候还是只能用普通写入。
aozima
2012-09-26
调网络不抓包,调I2C等时序不上逻辑分析仪,就像电工不用万用表!多用整理的好的文字,比截图更省流量,还能在整理过程中思考。
这些改动都有必要的,最初写驱动时只是先实现功能。
aozima
2012-09-26
调网络不抓包,调I2C等时序不上逻辑分析仪,就像电工不用万用表!多用整理的好的文字,比截图更省流量,还能在整理过程中思考。
关于问题1: ART的驱动中已经添加了SPI1与SPI3,realtouch中因为没有用到SPI1与SPI3,所以没有同步,现在已同步。 关于问题2 :DMA其实还应该加上判断:目标地址和源地址的数据对齐,以及目标地址和源地址是否在CCM区。 关于问题3:这个可以使用 completion 来实现。
SimonLeung
2013-10-23
这家伙很懒,什么也没写!
>关于问题1: ART的驱动中已经添加了SPI1与SPI3,realtouch中因为没有用到SPI1与SPI3,所以没有同步,现在已同步。 >关于问题2 :DMA其实还应该加上判断:目标地址和源地址的数据对齐,以及目标地址和源地址是否在CCM区。 >关于问题3:这个可以使用 completion 来实现。 --- completion是什么东东?
撰写答案
登录
注册新账号
关注者
0
被浏览
6.5k
关于作者
lzm0117
这家伙很懒,什么也没写!
提问
2
回答
7
被采纳
0
关注TA
发私信
相关问题
1
[项目]搞个开源的硬件项目
2
硬件计划贴,及时更新,欢迎提意见
3
软件计划贴,及时更新,欢迎提意见::WMA,MOUNT,LWIP等问题急需解决.
4
MMS协议
5
定点的wma解压库-libwma
6
QQ群记录 [20090821]
7
STM32网络收音机PCB报名征集
8
第一版调试记录
9
第二版硬件讨论
10
RADIO项目相关模块规格--欢迎大家自己做板时规格与此兼容,减少重复劳动
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
rt-thread 小内存算法源码分析
2
env中添加lvgl软件包后,keil编译包--c99错误
3
【NXP-MCXA153】 定时器驱动移植
4
GD32F450 看门狗驱动适配
5
【NXP-MCXA153】看门狗驱动移植
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
PWM
freemodbus
flash
cubemx
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
编译报错
Debug
rt_mq_消息队列_msg_queue
SFUD
keil_MDK
msh
ulog
C++_cpp
MicroPython
本月问答贡献
踩姑娘的小蘑菇
7
个答案
2
次被采纳
a1012112796
18
个答案
1
次被采纳
红枫
5
个答案
1
次被采纳
Ryan_CW
5
个答案
1
次被采纳
张世争
4
个答案
1
次被采纳
本月文章贡献
YZRD
3
篇文章
6
次点赞
catcatbing
3
篇文章
6
次点赞
lizimu
2
篇文章
11
次点赞
qq1078249029
2
篇文章
2
次点赞
xnosky
2
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部