STM32使用SPI+DMA(标准库)

DMA

DMA原理

DMA通道资源分配

SPI+DMA配置

主函数编写如下


DMA原理

1.CPU配置好DMA。

2.SPI发出DMA请求。(在DMA_Mode_Normal模式下,该请求实际上需要CPU命令SPI发出请求)

3.若该通道有多个请求,DMA控制器通过仲裁器判断,根据配置的优先级,选择先回应该通道高优先级的请求,再回应低优先级的请求。(此过程不需要CPU参与)

4.DMA控制器回应请求后,自动根据配置,进行数据传输。(此过程不需要CPU参与)

DMA请求CPU释放总线,当DMA传输完成后,DMA归还总线给CPU


DMA通道资源分配

DMA1通道

在这里插入图片描述

 DMA2通道

在这里插入图片描述


SPI+DMA配置

既然使用的是SPI+DMA,必定要使能SPI,详细请参考

SPI配置

配置完SPI后,配置DMA,如下

void dma_init(unsigned int SendBuff,unsigned int buffer_size)
{
 
DMA_InitTypeDef DMA_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
DMA_DeInit(DMA1_Channel3);
/*DMA配置*/

DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI1->DR;
//SPI数据寄存器地址
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)SendBuff; 
//内存地址(要传输的变量的指针)
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; 
//方向(从内存到外设)
//DMA_DIR_PeripheralSRC为从外设到内存
DMA_InitStructure.DMA_BufferSize = buffer_size; 
//传输内容的大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 
//外设地址不增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 
//内存地址自增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte ; 
//外设数据单位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte ; 
//内存数据单位
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ; 
//DMA模式:一次传输
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium ; 
//优先级:高
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; 
//禁止内存到内存的传输
 
DMA_Init(DMA1_Channel3, &DMA_InitStructure); 
//配置DMA1的3通道
DMA_Cmd(DMA1_Channel3, ENABLE);       //使能DMA
}

注意:DMA_PeripheralBaseAddr不是SPI外设的地址,而是SPI1->DR即SPI数据寄存器的地址

因为DMA_Mode_Normal模式使用一次后DMA_BufferSize会清零,如下代码用于重置DMA_BufferSize

void DMA_Buffercounter_reset(unsigned int buffer_size)
{ 
	DMA_Cmd(DMA1_Channel3, DISABLE );     
//失能DMA,使得DMA_SetCurrDataCounter能够使用
 	DMA_SetCurrDataCounter(DMA1_Channel3,buffer_size); 
//一次传输模式,DMA_BufferSize执行一次后会清零
//后续需要重复传输的时候,需要使用该函数再次设置DMA_BufferSize
 	DMA_Cmd(DMA1_Channel3, ENABLE);       
//使能DMA
}	

主函数编写如下

#define buff_size 256
unsigned char sendbuff[buff_size];

int mian(coid)
{
    dma_init((unsigned int)sendbuff,buff_size);
    while(1)
    {
        for(i=0 ;i<buff_size;i++)
		{
          sendbuff[i]=color;
		}
		for(i = 0 ; i<(32768/buff_size); i++)
		{
			
		  SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Tx,ENABLE); 
          //SPI向DMA发出请求,DMA会通过仲裁器自动回应请求 
		  DMA_Buffercounter_reset(buff_size);
          //重置DMA_BufferSize,为下一次DMA传送做好准备
		
		    while(1)
			{
				if(DMA_GetFlagStatus(DMA1_FLAG_TC3)!=RESET)//判断DMA是否传输完成
						{
							DMA_ClearFlag(DMA1_FLAG_TC3);//DMA传输完成,清除标志位
							break; 
						}
			}
		} 
    }

}

  • 18
    点赞
  • 154
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
以下是基于STM32标准库SPI DMA发送代码: ```c #include "stm32f10x.h" #define SPI_PORT SPI2 #define DMA_CHANNEL DMA1_Channel5 #define BUFFER_SIZE 16 uint8_t tx_buffer[BUFFER_SIZE] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10}; uint8_t rx_buffer[BUFFER_SIZE]; void SpiDmaSend(void) { /* Enable DMA clock */ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); /* Enable SPI clock */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE); /* Configure SPI pins */ GPIO_InitTypeDef gpio_init; gpio_init.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; gpio_init.GPIO_Mode = GPIO_Mode_AF_PP; gpio_init.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &gpio_init); /* Configure SPI */ SPI_InitTypeDef spi_init; spi_init.SPI_Direction = SPI_Direction_1Line_Tx; spi_init.SPI_Mode = SPI_Mode_Master; spi_init.SPI_DataSize = SPI_DataSize_8b; spi_init.SPI_CPOL = SPI_CPOL_Low; spi_init.SPI_CPHA = SPI_CPHA_1Edge; spi_init.SPI_NSS = SPI_NSS_Soft; spi_init.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; spi_init.SPI_FirstBit = SPI_FirstBit_MSB; SPI_Init(SPI_PORT, &spi_init); /* Enable SPI */ SPI_Cmd(SPI_PORT, ENABLE); /* Configure DMA */ DMA_InitTypeDef dma_init; dma_init.DMA_PeripheralBaseAddr = (uint32_t)&SPI_PORT->DR; dma_init.DMA_MemoryBaseAddr = (uint32_t)tx_buffer; dma_init.DMA_DIR = DMA_DIR_PeripheralDST; dma_init.DMA_BufferSize = BUFFER_SIZE; dma_init.DMA_PeripheralInc = DMA_PeripheralInc_Disable; dma_init.DMA_MemoryInc = DMA_MemoryInc_Enable; dma_init.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; dma_init.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; dma_init.DMA_Mode = DMA_Mode_Normal; dma_init.DMA_Priority = DMA_Priority_VeryHigh; dma_init.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA_CHANNEL, &dma_init); /* Enable DMA transfer complete interrupt */ DMA_ITConfig(DMA_CHANNEL, DMA_IT_TC, ENABLE); /* Start DMA transfer */ DMA_Cmd(DMA_CHANNEL, ENABLE); /* Wait for DMA transfer to complete */ while (DMA_GetFlagStatus(DMA1_FLAG_TC5) == RESET); /* Disable DMA and SPI */ DMA_Cmd(DMA_CHANNEL, DISABLE); SPI_Cmd(SPI_PORT, DISABLE); /* Disable DMA clock */ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, DISABLE); } /* DMA1 Channel5 Interrupt Handler */ void DMA1_Channel5_IRQHandler(void) { if (DMA_GetITStatus(DMA1_IT_TC5)) { /* Clear the DMA transfer complete interrupt flag */ DMA_ClearFlag(DMA1_FLAG_TC5); /* Disable DMA transfer complete interrupt */ DMA_ITConfig(DMA_CHANNEL, DMA_IT_TC, DISABLE); } } ``` 在主函数中,调用`SpiDmaSend()`函数即可实现SPI DMA发送。注意,在代码中使用DMA1 Channel5和SPI2,如需更改,请自行更改代码。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值