历史上的今天
今天是:2024年10月09日(星期三)
2020年10月09日 | STM32的SPI采用DMA方式传输测试
2020-10-09 来源:eefocus
环境:
主机:WIN7
开发环境:MDK4.23
MCU:STM32F103CBT6
说明:
参考链接:http://www.openedv.com/posts/list/3159.htm
SPI传输数据分为连续传输和非连续传输.
连续传输时序图:

非连续传输时序图:

非连续传输模式可以参考上篇文章:http://blog.csdn.net/jdh99/article/details/7598573
官方pdf关于连续和非连续传输的说明:
当在主模式下发送数据时,如果软件足够快,能够在检测到每次TXE的上升沿(或TXE中断),并立即在正在进行的传输结束之前写入SPI_DR寄存器,则能够实现连续的通信;此时,在每个数据项的传输之间的SPI时钟保持连续,同时BSY位不会被清除。
简而言之,就是要及时监测TXE.在SPI在1M以上波特率传输时,传输一位时间为1us,导致软件不能及时判断,此时可以用dma的方式来进行SPI传输.
源代码:
配置:
#define buffersize 512
#define SPI1_DR_Addr ( (u32)0x4001300C )
extern uint8_t SPI1_TX_Buff[buffersize];
extern uint8_t SPI1_RX_Buff[buffersize];
void SPI1_DMA_Configuration( void )
{
RCC->AHBENR |= 1<<0 ; //DMA1时钟使能
/*------------------配置SPI1_RX_DMA通道Channel2---------------------*/
DMA1_Channel2->CCR &= ~( 1<<14 ) ; //非存储器到存储器模式
DMA1_Channel2->CCR |= 2<<12 ; //通道优先级高
DMA1_Channel2->CCR &= ~( 3<<10 ) ; //存储器数据宽度8bit
DMA1_Channel2->CCR &= ~( 3<<8 ) ; //外设数据宽度8bit
DMA1_Channel2->CCR |= 1<<7 ; //存储器地址增量模式
DMA1_Channel2->CCR &= ~( 1<<6 ) ; //不执行外设地址增量模式
DMA1_Channel2->CCR &= ~( 1<<5 ) ; //执行循环操作
DMA1_Channel2->CCR &= ~( 1<<4 ) ; //从外设读
DMA1_Channel2->CNDTR &= 0x0000 ; //传输数量寄存器清零
DMA1_Channel2->CNDTR = buffersize ; //传输数量设置为buffersize个
DMA1_Channel2->CPAR = SPI1_DR_Addr ; //设置外设地址,注意PSIZE
DMA1_Channel2->CMAR = (u32)SPI1_RX_Buff ; //设置DMA存储器地址,注意MSIZE
/*------------------配置SPI1_TX_DMA通道Channel3---------------------*/
DMA1_Channel3->CCR &= ~( 1<<14 ) ; //非存储器到存储器模式
DMA1_Channel3->CCR |= 0<<12 ; //通道优先级最低
DMA1_Channel3->CCR &= ~( 3<<10 ) ; //存储器数据宽度8bit
DMA1_Channel3->CCR &= ~( 3<<8 ) ; //外设数据宽度8bit
DMA1_Channel3->CCR |= 1<<7 ; //存储器地址增量模式
DMA1_Channel3->CCR &= ~( 1<<6 ) ; //不执行外设地址增量模式
DMA1_Channel3->CCR &= ~( 1<<5 ) ; //不执行循环操作
DMA1_Channel3->CCR |= 1<<4 ; //从存储器读
DMA1_Channel3->CNDTR &= 0x0000 ; //传输数量寄存器清零
DMA1_Channel3->CNDTR = buffersize ; //传输数量设置为buffersize个
DMA1_Channel3->CPAR = SPI1_DR_Addr ; //设置外设地址,注意PSIZE
DMA1_Channel3->CMAR = (uint32_t)SPI1_TX_Buff ; //设置DMA存储器地址,注意MSIZE
}
接收与发送:
void SPI1_ReceiveSendByte( u16 num )
{
DMA1_Channel2->CNDTR = 0x0000 ; //传输数量寄存器清零
DMA1_Channel2->CNDTR = num ; //传输数量设置为buffersize个
DMA1_Channel3->CNDTR = 0x0000 ; //传输数量寄存器清零
DMA1_Channel3->CNDTR = num ; //传输数量设置为buffersize个
DMA1->IFCR = 0xF0 ; //清除通道2的标志位
DMA1->IFCR = 0xF00 ; //清除通道3的标志位
SPI1->DR ; //接送前读一次SPI1->DR,保证接收缓冲区为空
while( ( SPI1->SR & 0x02 ) == 0 );
DMA1_Channel3->CCR |= 1 << 0 ; //开启DMA通道3
DMA1_Channel2->CCR |= 1 << 0 ; //开启DMA通道2
while( ( DMA1->ISR & 0x20 ) == 0 );
DMA1_Channel3->CCR &= ~( 1 << 0 ) ; //关闭DMA通道3
DMA1_Channel2->CCR &= ~( 1 << 0 ) ; //关闭DMA通道2
}
//SPI发送一个字节
static uint8 SPI_SendByte(uint8 Data)
{
#ifndef SPI_DMA
// Loop while DR register in not emplty
while( SPI_I2S_GetFlagStatus( SPI1, SPI_I2S_FLAG_TXE ) == RESET ) ;
// Send byte through the SPI1 peripheral
SPI_I2S_SendData( SPI1, Data ) ;
// Wait to receive a byte
while( SPI_I2S_GetFlagStatus( SPI1, SPI_I2S_FLAG_RXNE ) == RESET ) ;
// Return the byte read from the SPI bus
return SPI_I2S_ReceiveData( SPI1 ) ;
#else
SPI1_TX_Buff[0] = Data;
SPI1_ReceiveSendByte(1);
return (SPI1_RX_Buff[0]);
#endif
}
//SPI读取Len字节
void SPI_ReadBytes( uint8 Addr, NtrxBufferPtr Buffer, uint8 Len )
{
#ifndef SPI_DMA
if( ( Len > 0x80 ) || ( Len == 0 ) )
Len = 1 ;
SPI_SendByte( Len ) ;
SPI_SendByte( Addr ) ;
while( Len-- )
{
*Buffer = SPI_SendByte( 0xFF ) ;
Buffer ++ ;
}
#else
uint8 i = 0;
if( ( Len > 0x80 ) || ( Len == 0 ) )
Len = 1 ;
SPI1_TX_Buff[0] = Len;
SPI1_TX_Buff[1] = Addr;
SPI1_ReceiveSendByte(Len + 2);
for (i = 0;i < Len;i++)
{
*Buffer++ = SPI1_RX_Buff[i + 2];
}
#endif
}
史海拾趣
|
BT3C扫频仪校正扫频信号时,得不到矩形的波形。相应的设置为:全扫,频标50M,衰减为0,观测到的扫频信号中间有个突起的波峰,两边有一些小突起,然后最边上有一小段平线。 按理应该看到的是基本是一个矩形,可是为什么得不到呢?应该如何调整,还 ...… 查看全部问答> |
|
AnalogicTech offers a complete portfolio of products for smartphones and other handheld equipment to fully optimize available energy, minimize losses, and prolong battery life. For Li-ion polymer batteries, linear & ...… 查看全部问答> |
|
LED由于环保、寿命长、光电效率高等众多优点,近年来在各行业应用得以快速发展,LED的驱动电源成了关注热点,理论上,LED的使用寿命在10万小时以上,但在实际应用过程中,由于驱动电源的设计及驱动方式选择不当,使LED极易损坏.随着LED的应用日益广泛,LED ...… 查看全部问答> |
|
windows mobile 6中MessageBox.Show()调用的参数问题! 我用的是windows mobile 6的系统,但是调用MessageBox这个函数却无法使用后面两个参数即:MessageBoxButtons,MessageBoxIcon. 程序中也无法包含System.Windows.Forms.MessageButtons..这个命名空间。 但是我的系统里其他的程序(windows mobile ...… 查看全部问答> |
|
大家好,我最近在帮一个朋友写一鼠标过滤驱动,需要拦截鼠标的按键,以及按下按键时候的鼠标坐标。这样才可以把鼠标的所有动作给回放出来。 现在碰到的问题是,如何在不需要应用程序作为辅助的情况下面,直接在驱动程序中就得到鼠标的坐标。(现在 ...… 查看全部问答> |
|
我用CAB打包后,出的错误Log文件的内容是 “Error: Section [SourceDisksFiles] - file D:\\Program Files\\HelloCE\\HelloCE\\bin\\Debug\\HelloCE.exe cannot have a drive or pathname” 请问是什么原因?谢谢… 查看全部问答> |




