一是想总结一下SPI总线的特色与留意点,二是总结一下SPI DMA的运用
一、SPI信号线阐明
一般SPI经过4个引脚与外部器材相连:
- MISO:主设备输入/从设备输出引脚。该引脚在从形式下发送数据,在主形式下接纳数据。
- MOSI:主设备输出/从设备输入引脚。该引脚在主形式下发送数据,在从形式下接纳数据。
- SCK:串口时钟,作为主设备的输出,从设备的输入
- NSS:从设备挑选。这是一个可选的引脚,用来挑选主/从设备。它的功用是用来作为“片选引脚”,让主设备能够单独地与特定从设备通讯,防止数据线上的抵触。
二、原理
MOSI脚相互连接,MISO脚相互连接。这样,数据在主和从之间串行地传输(MSB位在前)。
通讯总是由主设备建议。主设备经过MOSI脚把数据发送给从设备,从设备经过MISO引脚回传数据。这意味全双工通讯的数据输出和数据输入是用同一个时钟信号同步的;时钟信号由主设备经过SCK脚供给。
NSS分为内部引脚和外部引脚。
NSS外部引脚能够作为输入信号或许输出信号,输入信号一般用作硬件方法从机的片选,而输出信号一般用于主SPI去片选与之相连的从SPI。
NSS从设备挑选有两种形式:
1、软件形式
能够经过设置SPI_CR1寄存器的SSM位来使能这种形式,当它为1时,NSS引脚上的电平由SSI决议。在这种形式下NSS外部引脚能够用作它用,而内部NSS信号电平能够经过写SPI_CR1的SSI位来驱动。
2、硬件形式
两种方法:
(1)关于主SPI,NSS能够直接接高电平,关于从SPI,能够直接接低电平。
(2)当STM32F10xxx作业为主SPI,而且NSS输出现已经过SPI_CR2寄存器的SSOE位使能,这时主机的NSS讲作为输出信号,引脚信号被拉低,一切NSS引脚与这个主SPI的NSS引脚相连并装备为硬件NSS的SPI设备,将主动变成从SPI设备。
此刻两个的NSS信号线能够接个上拉电阻直连。
四、DMA阐明
DMA是AMBA的先进高功能总线(AHB)上的设备,它有2个AHB端口:一个是从端口,用于装备DMA,另一个是主端口,使得DMA能够在不同的从设备之间传输数据。
DMA的作用是在没有Cortex-M3中心的干涉下,在后台完结数据传输。在传输数据的进程中,主处理器能够碑文其它使命,只要在整个数据块传输完毕后,需求处理这些数据时才会中止主处理器的操作。它能够在对体系功能发生较小影响的情况下,完结很多数据的传输。
五、SPI_DMA的通讯进程
- 设置外设地址
- 设置存储器地址
- 设置传输数据量
- 设置通道的装备信息
- 使能DMA通道,发动传输
- 发送时,在每次TXE被设置为’1’时宣布DMA恳求,DMA控制器则写数据至SPI_DR寄存器,TXE标志因此而被铲除。
- 接纳时,在每次RXNE被设置为’1’时宣布DMA恳求,DMA控制器则从SPI_DR寄存器读出数据,RXNE标志因此而被铲除。
六、相关代码
这儿运用的是SPI1
SPI_DMA装备
1 /*******************************************************************************2 * Function Name : SPI1_DMA_Configuration3 * Description : 装备SPI1_RX的DMA通道2,SPI1_TX的DMA通道34 * Input : None5 * Output : None6 * Return : None7 * Attention : 8 *******************************************************************************/9 void SPI1_DMA_Configuration( void )10 {11 DMA_InitTypeDef DMA_InitStructure;12 13 /* DMA1 Channel2 (triggered by SPI1 Rx event) Config */14 DMA_DeInit(DMA1_Channel2); 15 DMA_InitStructure.DMA_PeripheralBaseAddr = SPI1_DR_Addr; //设置 SPI1 发送外设(0x4001300C) 地址(意图地址)16 DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)SPI1_RX_Buff; //设置 SRAM 存储地址(意图地址)17 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //传输方向 外设-内存18 DMA_InitStructure.DMA_BufferSize = SPI1_ReciveBufferSize; //设置 SPI1 发送长度19 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;20 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;21 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;22 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;23 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;24 DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;25 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;26 DMA_Init(DMA1_Channel2, &DMA_InitStructure);27 28 DMA_ITConfig(DMA1_Channel2, DMA_IT_TC, ENABLE);29 /* Enable SPI1 DMA RX request */30 SPI1->CR2 = 1<<0; //接纳缓冲区DMA使能31 DMA_Cmd(DMA1_Channel2, ENABLE);32 33 34 /* DMA1 Channel3 (triggered by SPI1 Tx event) Config */35 DMA_DeInit(DMA1_Channel3); 36 DMA_InitStructure.DMA_PeripheralBaseAddr = SPI1_DR_Addr; //设置 接纳外设(0x4001300C) 地址(源地址)37 DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)SPI1_TX_Buff; //设置 SRAM 存储地址(源地址)38 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //传输方向 内存-外设39 DMA_InitStructure.DMA_BufferSize = SPI1_SendBufferSize; //设置 SPI1 接纳长度40 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址增量(不变)41 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址增量(改变)42 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设传输宽度(字节)43 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //内存传输宽度(字节)44 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //传输方法,一次传输完中止,不从头加载45 DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; //中止方法-高(三级)46 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //内存到内存方法制止47 DMA_Init(DMA1_Channel3, &DMA_InitStructure);48 49 DMA_ITConfig(DMA1_Channel3, DMA_IT_TC, ENABLE); //舱位 DMA1_Channel3 传输完结中止50 DMA_ITConfig(DMA1_Channel3, DMA_IT_TE, ENABLE); //舱位 DMA1_Channel3 传输过错中止51 /* Enable SPI1 DMA TX request */52 SPI1->CR2 = 1<<1; //发送缓冲区DMA使能53 DMA_Cmd(DMA1_Channel3, DISABLE); //舱位 DMA 通道 DMA1_Channel354 }
SPI发送
1 /*******************************************************************************2 * Function Name : SPI1_Send3 * Description : SPI1的DMA方法发送4 * Input : SPI1_TX_Buff[SPI1_SendBufferSize]5 * Output : None6 * Return : None7 * Attention : 封闭DMA通道3之前有必要等候TXE为1,等候忙标志为08 *******************************************************************************/9 void SPI1_Send( u8 *buff, u32 len )10 {11 DMA1_Channel3->CPAR = SPI1_DR_Addr; //外设地址12 DMA1_Channel3->CMAR = (u32) buff; //mem地址13 DMA1_Channel3->CNDTR = len ; //传输长度14 DMA1_Channel3->CCR = (0 << 14) // 非存储器到存储器形式15 (2 << 12) // 通道优先级高16 (0 << 11) // 存储器数据宽度8bit17 (0 << 10) // 存储器数据宽度8bit18 (0 << 9) // 外设数据宽度8bit19 (0 << 8) // 外设数据宽度8bit20 (1 << 7) // 存储器地址增量形式21 (0 << 6) // 外设地址增量形式(不增)22 (0 << 5) // 非循环形式23 (1 << 4) // 从存储器读24 (1 << 3) // 答应传输过错中止25 (0 << 2) // 答应半传输中止26 (1 << 1) // 答应传输完结中止27 (1); // 通道舱位28 }
SPI接纳
1 /*******************************************************************************2 * Function Name : SPI1_Recive3 * Description : SPI1的DMA方法接纳4 * Input : None5 * Output : SPI1_RX_Buff[SPI1_ReciveBufferSize]6 * Return : None7 * Attention : 有必要要先封闭通道2,然后再装备通道2的参数8 *******************************************************************************/9 void SPI1_Recive( u8 *buff, u32 len )10 {11 DMA1_Channel2->CCR &= ~( 1 << 0 ); //封闭DMA通道212 13 DMA1_Channel2->CPAR = SPI1_DR_Addr; //外设地址14 DMA1_Channel2->CMAR = (uint32_t)buff; //mem地址15 DMA1_Channel2->CNDTR = len ; //传输长度16 DMA1_Channel2->CCR = (0 << 14) // 非存储器到存储器形式17 (2 << 12) // 通道优先级高18 (0 << 11) // 存储器数据宽度8bit19 (0 << 10) // 存储器数据宽度8bit20 (0 << 9) // 外设数据宽度8bit21 (0 << 8) // 外设数据宽度8bit22 (1 << 7) // 存储器地址增量形式23 (0 << 6) // 外设地址增量形式(不增)24 (0 << 5) // 非循环形式25 (0 << 4) // 传输方向 外设-内存26 (0 << 3) // 答应传输过错中止27 (0 << 2) // 答应半传输中止28 (1 << 1) // 答应传输完结中止29 (1); // 通道舱位30 }