stm32 DMA数据搬运 [操作寄存器+库函数](转)

源:stm32 DMA数据搬运 [操作寄存器+库函数]

DMA(Direct Memory Access)常译为“存储器直接存取”。早在Intel的8086平台上就有了DMA应用了。

一个完整的微控制器通常由CPU、存储器和外设等组件构成。这些组件一般在结构和功能上都是独立的,而各个组件的协调和交互就由CPU完成。如此一来,CPU作为整个芯片的核心,其处理的工作量是很大的。如果CPU先从A外设拿到一个数据送给B外设使用,同时C外设又需要D外设提供一个数据。。。这样的数据搬运工作将使CPU的负荷显得相当繁重。

严格的说,搬运数据只是CPU的比较不重要的一种工作。CPU最重要的工作室进行数据运算,从加减乘除到一些高级的运算,包括浮点、积分、微分、FFT等。CPU还需要负责复杂的中断申请和响应,以保证芯片的实时性能。

理论上常见的控制外设,比如Usart、I2C、SPI甚至是USB等通信接口,单纯的利用CPU进行协议模拟也是可以实现的,比如51单片机经常使用I/O口模拟I2C协议通信。但这样既浪费了CPU的资源,同时实现后的性能表现往往和使用专门的硬件模块实现的效果相差甚远。从这个角度来看,各个外设控制器的存在,无疑降低了CPU的负担,解放了CPU的资源。

数据搬运这一工作占用了大部分的CPU资源,成为了降低CPU的工作效率的主要原因之一。于是需要一种硬件结构分担CPU这一职能 —— DMA。

从数据搬运的角度看,如果要把存储地址A的数值赋给另外一个地址上B的变量,CPU实现过程为首先读出A地址上的数据存储在一个中间变量,然后再转送到B地址的变量上。使用DMA则不需要中间变量,直接将A地址的数值传送到B地址的变量里。无疑减轻了CPU的负担,也提高了数据搬运的效率。

stm32中 DMA1有7个通道,DMA2有5个通道。DMA挂载的时钟为AHB总线,其时钟为72Mhz,所以可以实现高速数据搬运。

stm32的DMA1通道一览表

本例实现使用CPU和DMA搬运同一组数据,通过计时,比较两者的搬运效率。

直接操作寄存器

DMA的中断状态寄存器(DMA_ISR):

TEIFx:通道x的传输错误标志(x = 1 … 7) (Channel x transfer error flag) 硬件设置这些位。在DMA_IFCR寄存器的相应位写入’1’可以清除这里对应的标志位。

0:在通道x没有传输错误(TE);             1:在通道x发生了传输错误(TE)。

HTIFx:通道x的半传输标志(x = 1 … 7) (Channel x half transfer flag) 硬件设置这些位。在DMA_IFCR寄存器的相应位写入’1’可以清除这里对应的标志位。

0:在通道x没有半传输事件(HT);         1:在通道x产生了半传输事件(HT)。

TCIFx:通道x的传输完成标志(x = 1 … 7) (Channel x transfer complete flag) 硬件设置这些位。在DMA_IFCR寄存器的相应位写入’1’可以清除这里对应的标志位。

0:在通道x没有传输完成事件(TC);       1:在通道x产生了传输完成事件(TC)。

DMA_IFCR中断标志清除寄存器:

结构类似DMA_ISR。

CTEIFx:清除通道x的传输错误标志(x = 1 … 7) (Channel x transfer error clear) 这些位由软件设置和清除。     0:不起作用         1:清除DMA_ISR寄存器中的对应TEIF标志。

CHTIFx:清除通道x的半传输标志(x = 1 … 7) (Channel x half transfer clear) 这些位由软件设置和清除。           0:不起作用         1:清除DMA_ISR寄存器中的对应HTIF标志。

CTCIFx:清除通道x的传输完成标志(x = 1 … 7) (Channel x transfer complete clear) 这些位由软件设置和清除。 0:不起作用        1:清除DMA_ISR寄存器中的对应TCIF标志。

CGIFx:清除通道x的全局中断标志(x = 1 … 7) (Channel x global interrupt clear) 这些位由软件设置和清除。    0:不起作用         1:清除DMA_ISR寄存器中的对应的GIF、TEIF、HTIF和TCIF标志。

DMA通道配置寄存器(DMA_CCRx):

MEM2MEM:存储器到存储器模式 (Memory to memory mode) 该位由软件设置和清除。 0:非存储器到存储器模式; 1:启动存储器到存储器模式。

PL:通道优先级 (Channel priority level)  这些位由软件设置和清除。 00:低 01:中 10:高 11:最高

MSIZE:存储器数据宽度 (Memory size) 这些位由软件设置和清除。 00:8位 01:16位 10:32位 11:保留

PSIZE:外设数据宽度 (Peripheral size)  这些位由软件设置和清除。 00:8位 01:16位 10:32位 11:保留

MINC:存储器地址增量模式 (Memory increment mode)  该位由软件设置和清除。 0:不执行存储器地址增量操作 1:执行存储器地址增量操作

PINC:外设地址增量模式 (Peripheral increment mode) 该位由软件设置和清除。 0:不执行外设地址增量操作 1:执行外设地址增量操作

CIRC:循环模式 (Circular mode)  该位由软件设置和清除。 0:不执行循环操作 1:执行循环操作

DIR:数据传输方向 (Data transfer direction)   该位由软件设置和清除。 0:从外设读 1:从存储器读

TEIE:允许传输错误中断 (Transfer error interrupt enable)  该位由软件设置和清除。 0:禁止TE中断 0:允许TE中断

HTIE:允许半传输中断 (Half transfer interrupt enable) 该位由软件设置和清除。 0:禁止HT中断 0:允许HT中断

TCIE:允许传输完成中断 (Transfer complete interrupt enable) 该位由软件设置和清除。 0:禁止TC中断 0:允许TC中断

EN:通道开启 (Channel enable) 该位由软件设置和清除。 0:通道不工作 1:通道开启

DMA通道x传输数量寄存器(DMA_CNDTRx)(x = 1…7)

低16位有效。这个寄存器控制通道每次传输的数据量,数据传输数量为0至65535。该寄存器会随着传输的进行而递减,为0表示已经发送完成。

DMA外设地址寄存器(DMA_CPARx)

32位寄存器。外设数据寄存器的基地址,作为数据传输的源或目标。

DMA存储地址寄存器(DMA_CMARx)

存储器地址[31:0],存储器地址作为数据传输的源或目标。

代码如下:  (system.h 和 stm32f10x_it.h 等相关代码参照 stm32 直接操作寄存器开发环境配置

User/main.c

#include <stm32f10x_lib.h>
#include "system.h"
#include "usart.h"
#include "dma.h"
#include "tim.h"
#include "string.h"

#define LED1 PAout(4)
#define LED2 PAout(5)
#define LED3 PAout(6)

void Gpio_Init(void);

//数据源
uc32 SRC_Const_Buffer[32] =
{
    0x01020304,0x05060708,0x090A0B0C,0x0D0E0F10,
    0x11121314,0x15161718,0x191A1B1C,0x1D1E1F20,
    0x21222324,0x25262728,0x292A2B2C,0x2D2E2F30,
    0x31323334,0x35363738,0x393A3B3C,0x3D3E3F40,
    0x41424344,0x45464748,0x494A4B4C,0x4D4E4F50,
    0x51525354,0x55565758,0x595A5B5C,0x5D5E5F60,
    0x61626364,0x65666768,0x696A6B6C,0x6D6E6F70,
    0x71727374,0x75767778,0x797A7B7C,0x7D7E7F80
};

//目标位置
u32 DST_Buffer[32];

int main(void)
{
    u8 i=0;
    u16 StartTime=0,CPUSpendTime=0,DMASpendTime=0;;

    Rcc_Init(9);                            //系统时钟设置

    Usart1_Init(72,9600);

    Tim_Init(TIM_2,65535,71);            //初始化TIM2定时器,设定重装值和分频值,计时时间为1us/次

    Dma_Init(DMA1_Channel1,(u32)SRC_Const_Buffer,(u32)DST_Buffer);    //初始化DMA,外设地址示例 &USART1->DR

    Nvic_Init(1,0,DMA1_Channel1_IRQChannel,4);      //设置抢占优先级为0,响应优先级为0,中断分组为4

    Gpio_Init();

    StartTime = TIM2->CNT;

    while(i<32)                             //CPU搬运
    {
        DST_Buffer[i]=SRC_Const_Buffer[i];
        i++;
    }

    CPUSpendTime = TIM2->CNT - StartTime;

    printf("\r\n the CPU spend : %dus! \r\n",CPUSpendTime);

    if(strncmp((const char *)SRC_Const_Buffer,(const char *)DST_Buffer,32) ==0)      //验证传输效果,判断两数组是否相同
    {
        printf("\r\n CPU Transmit Success! \r\n");
    }else{
        printf("\r\n CPU Transmit Fail! \r\n");
    }

    i=0;

    while(i<32)                            //清空目标数组,准备DMA搬运
    {
        DST_Buffer[i]=0;
        i++;
    }  

    StartTime = TIM2->CNT;

    Dma_Enable(DMA1_Channel1,32);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//DMA搬运

    while( DMA1_Channel1 -> CNDTR != 0);        //等待传输完成

    DMASpendTime= TIM2->CNT - StartTime;

    printf("\r\n the DMA spend : %dus! \r\n",DMASpendTime);

    if(strncmp((const char *)SRC_Const_Buffer,(const char *)DST_Buffer,32) ==0)      //验证传输效果,判断两数组是否相同
    {
        printf("\r\n DMA Transmit Success! \r\n");
    }else{
        printf("\r\n DMA Transmit Fail! \r\n");
    }     

    while(1);
}

void Gpio_Init(void)
{
    RCC->APB2ENR|=1<<2;    //使能PORTA时钟     

    GPIOA->CRL&=0x0000FFFF; // PA0~3设置为浮空输入,PA4~7设置为推挽输出
    GPIOA->CRL|=0x33334444; 

    //USART1 串口I/O设置

    GPIOA -> CRH&=0xFFFFF00F;   //设置USART1 的Tx(PA.9)为第二功能推挽,50MHz;Rx(PA.10)为浮空输入
    GPIOA -> CRH|=0x000008B0;      

}

User/stm32f10x_it.c

#include "stm32f10x_it.h"
#include "system.h"
#include "stdio.h"

#define LED1 PAout(4)
#define LED2 PAout(5)
#define LED3 PAout(6)
#define LED4 PAout(7)

void DMAChannel1_IRQHandler(void)  //和启动文件有关,STM32F10x.s中 和  STM32F10x_md.s DMA中断接口函数不同
{

    if( DMA1 ->ISR & (1<<1))        //传输完成中断
    {

        LED1 = 1;
        DMA1->IFCR |= 1<<1;    //清除传输完成中断
    }

    if( DMA1 ->ISR & (1<<2))        //半传输完成中断
    {

        DMA1 ->IFCR |= 1<<2;    //清除半传输完成中断
    }

    if( DMA1 ->ISR & (1<<3))        //传输错误中断
    {
        LED4 =1 ;
        DMA1 ->IFCR |= 1<<3;    //清除传输错误中断
    }

    DMA1 ->IFCR |= 1<<0;        //清除此通道的中断
}

Library/src/dma.c

#include <stm32f10x_lib.h>
#include "system.h"
#include "dma.h"

//DMA通道初始化函数
//传输方向:存储器 -> 存储器模式 ,32位数据模式,存储器增量模式
//参数说明:
//            DMA_CHx         :选择DMA控制器通道,DMA1有1-7,DMA2有1-4
//            P_Adress     :外设地址
//            M_Adress     :存储器地址

void Dma_Init(DMA_Channel_TypeDef * DMA_CHx,u32 P_Address ,u32 M_Address)
{

    RCC->AHBENR |= 1<<0;

    DMA_CHx -> CCR  &= 0xFFFF0000;        //复位      

    DMA_CHx -> CCR  |= 1<<1;            //允许传输完成中断
    //DMA_CHx -> CCR  |= 1<<2;            //允许半传输中断
    DMA_CHx -> CCR  |= 1<<3;            //允许传输错误中断 读写一个保留的地址区域,将会产生DMA传输错误  

    //设定数据传输方向
    DMA_CHx -> CCR  |= 0<<4;            //设定数据传输方向   0:从外设读 1:从存储器读
    DMA_CHx -> CCR  |= 0<<5;            //0:不执行循环操作 1:执行循环操作            

    //设定地址增量
    DMA_CHx -> CCR  |= 1<<6;            //0:不执行外设地址增量操作 1:执行外设地址增量操作
    DMA_CHx -> CCR  |= 1<<7;            //0:不执行存储器地址增量操作 1:执行存储器地址增量操作        

    //设定外设数据宽度    S
    DMA_CHx -> CCR  |= 0<<8;            //外设数据宽度,由[9:8]两位控制
    DMA_CHx -> CCR  |= 1<<9;            //00:8位 01:16位 10:32位 11:保留   

    //设定存储数据宽度
    DMA_CHx -> CCR  |= 0<<10;            //存储器数据宽度,由[11:10]两位控制
    DMA_CHx -> CCR  |= 1<<11;            //00:8位 01:16位 10:32位 11:保留   

    //设定为中等优先级
    DMA_CHx -> CCR  |= 1<<12;            //通道优先级,由[13:12]两位控制
    DMA_CHx -> CCR  |= 1<<13;            //00:低 01:中 10:高 11:最高       

    DMA_CHx -> CCR  |= 1<<14;            //0:非存储器到存储器模式; 1:启动存储器到存储器模式。        

    //必须配置好通道后配置地址
    DMA_CHx -> CPAR = (u32)P_Address;    //设定外设寄存器地址
    DMA_CHx -> CMAR = (u32)M_Address;    //设定数据存储器地址

}

//DMA通道使能
//参数说明:
//            DMA_CHx         :选择DMA控制器通道,DMA1有1-7,DMA2有1-4
//            Number       :数据传输量
void Dma_Enable(DMA_Channel_TypeDef * DMA_CHx,u16 Number)
{
    DMA_CHx -> CCR &= ~(1<<0);        //关闭上一次DMA传输
    DMA_CHx    -> CNDTR = Number;        //数据传输量
    DMA_CHx -> CCR |= 1<<0;            //开始DMA传输
}

Library/inc/dma.h

#include <stm32f10x_lib.h>    

void Dma_Init(DMA_Channel_TypeDef * DMA_CHx,u32 P_Adress ,u32 M_Address);
void Dma_Enable(DMA_Channel_TypeDef * DMA_CHx,u16 Number);

直接操作寄存器输出:

the CPU spend : 972us!

CPU Transmit Success!

the DMA spend : 5us!

DMA Transmit Success!

库函数操作

mian.c

#include "stm32f10x.h"
#include "stdio.h"
#include "string.h"

#define     PRINTF_ON  1
#define  BufferSize  32

vu16 LeftDataCounter;
vu32 Tick;

uc32 SRC_Const_Buffer[BufferSize] =
{
    0x01020304,0x05060708,0x090A0B0C,0x0D0E0F10,
    0x11121314,0x15161718,0x191A1B1C,0x1D1E1F20,
    0x21222324,0x25262728,0x292A2B2C,0x2D2E2F30,
    0x31323334,0x35363738,0x393A3B3C,0x3D3E3F40,
    0x41424344,0x45464748,0x494A4B4C,0x4D4E4F50,
    0x51525354,0x55565758,0x595A5B5C,0x5D5E5F60,
    0x61626364,0x65666768,0x696A6B6C,0x6D6E6F70,
    0x71727374,0x75767778,0x797A7B7C,0x7D7E7F80
};

u32 DST_Buffer[BufferSize];
u8 i=0,DMASpendTime=0,CPUSpendTime=0;

void RCC_Configuration(void);
void GPIO_Configuration(void);
void NVIC_Configuration(void);
void USART_Configuration(void);
void DMA_Configuration(void);

int main(void)
{
      RCC_Configuration();
      GPIO_Configuration();
    NVIC_Configuration();
    USART_Configuration();
    DMA_Configuration();

    SysTick_Config(72);

    Tick = 0;
    while(i<BufferSize)
    {
        DST_Buffer[i]=SRC_Const_Buffer[i];
        CPUSpendTime = Tick;
        i++;
    }
    i=0;
      while(i<BufferSize)
    {
        DST_Buffer[i]=0;
        i++;
    }

    Tick = 0;
    DMA_Cmd(DMA1_Channel6,ENABLE);
    while(LeftDataCounter != 0);    //等待传输完成
    DMASpendTime = Tick;

    if(strncmp((const char *)SRC_Const_Buffer,(const char *)DST_Buffer,BufferSize) ==0)
    {
        printf("\r\n Transmit Success! \r\n");
    }else{
         printf("\r\n Transmit Fail! \r\n");
    }

    printf("\r\n the CPU spend : %dus! \r\n",CPUSpendTime);
    printf("\r\n the DMA spend : %dus! \r\n",DMASpendTime);

}

void DMA_Configuration(void)
{
    DMA_InitTypeDef DMA_InitStructure;

    DMA_DeInit(DMA1_Channel6);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32) SRC_Const_Buffer;
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32) DST_Buffer;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize = BufferSize;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;
    DMA_Init(DMA1_Channel6,&DMA_InitStructure);

    DMA_ITConfig(DMA1_Channel6,DMA_IT_TC,ENABLE);
}

void GPIO_Configuration(void)
{
      GPIO_InitTypeDef GPIO_InitStructure;
       GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
      GPIO_Init(GPIOA , &GPIO_InitStructure);
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
      GPIO_Init(GPIOA , &GPIO_InitStructure); 

}

void RCC_Configuration(void)
{
    /* 定义枚举类型变量 HSEStartUpStatus */
    ErrorStatus HSEStartUpStatus;

      /* 复位系统时钟设置*/
      RCC_DeInit();
      /* 开启HSE*/
      RCC_HSEConfig(RCC_HSE_ON);
      /* 等待HSE起振并稳定*/
      HSEStartUpStatus = RCC_WaitForHSEStartUp();
    /* 判断HSE起是否振成功,是则进入if()内部 */
      if(HSEStartUpStatus == SUCCESS)
      {
        /* 选择HCLK(AHB)时钟源为SYSCLK 1分频 */
        RCC_HCLKConfig(RCC_SYSCLK_Div1);
        /* 选择PCLK2时钟源为 HCLK(AHB) 1分频 */
        RCC_PCLK2Config(RCC_HCLK_Div1);
        /* 选择PCLK1时钟源为 HCLK(AHB) 2分频 */
        RCC_PCLK1Config(RCC_HCLK_Div2);
        /* 设置FLASH延时周期数为2 */
        FLASH_SetLatency(FLASH_Latency_2);
        /* 使能FLASH预取缓存 */
        FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
        /* 选择锁相环(PLL)时钟源为HSE 1分频,倍频数为9,则PLL输出频率为 8MHz * 9 = 72MHz */
        RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
        /* 使能PLL */
        RCC_PLLCmd(ENABLE);
        /* 等待PLL输出稳定 */
        while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
        /* 选择SYSCLK时钟源为PLL */
        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
        /* 等待PLL成为SYSCLK时钟源 */
        while(RCC_GetSYSCLKSource() != 0x08);
      }
      /* 打开APB2总线上的GPIOA时钟*/
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1, ENABLE);
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    //RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR|RCC_APB1Periph_BKP|RCC_APB1Periph_WWDG, ENABLE);

}

void USART_Configuration(void)
{
    USART_InitTypeDef USART_InitStructure;
    USART_ClockInitTypeDef USART_ClockInitStructure;

    USART_ClockInitStructure.USART_Clock = USART_Clock_Disable;
    USART_ClockInitStructure.USART_CPOL = USART_CPOL_Low;
    USART_ClockInitStructure.USART_CPHA = USART_CPHA_2Edge;
    USART_ClockInitStructure.USART_LastBit = USART_LastBit_Disable;
    USART_ClockInit(USART1 , &USART_ClockInitStructure);

    USART_InitStructure.USART_BaudRate = 9600;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx|USART_Mode_Tx;
    USART_Init(USART1,&USART_InitStructure);

     USART_Cmd(USART1,ENABLE);
}

void NVIC_Configuration(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);    

    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel6_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

#if     PRINTF_ON

int fputc(int ch,FILE *f)
{
    USART_SendData(USART1,(u8) ch);
    while(USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET);
    return ch;
}

#endif

stm32f10x_it.c

#include "stm32f10x_it.h"
#include "stdio.h"

extern vu32 Tick;
extern vu16 LeftDataCounter;

void SysTick_Handler(void)
{
     Tick++;
}

void DMA1_Channel6_IRQHandler(void)
{

    LeftDataCounter = DMA_GetCurrDataCounter(DMA1_Channel6);   //获取剩余待传输数据
    DMA_ClearITPendingBit(DMA1_IT_GL6);
}

库函数输出:

Transmit Success!

the CPU spend : 68us!

the DMA spend : 7us!

时间: 2024-10-11 23:14:44

stm32 DMA数据搬运 [操作寄存器+库函数](转)的相关文章

stm32 NVIC中断管理实现[直接操作寄存器]

本文转自:http://www.ichanging.org/stm32_NVIC.html cortex-m3支持256个中端,其中包含了16个内核中断,240个外部中断.stm32只有84个中断,包括16个内核中断和68个可屏蔽中断.stm32f103上只有60个中断,f107上才有68个中断. 中断是stm32很基础的一个功能,学会使用中断,才可以更好的使用其他的外设.理解stm32的中断,必须要先从stm32的中断优先级分组是怎么回事.要理解优先级分组,就要先理解什么是先占优先级,和次占优

STM32与STM8操作寄存器的区别

在STM8中,由于STM8寄存器较少,在头文件中定义寄存器的时候不用采取任何形式的封装,所以操作寄存器的时候直接可以用如下方式处理:PB_DDR |=0x20; 但是在STM32中,由于其寄存器实在太多,不方便像STM8一样定义头文件,而采用大量的结构体指针,宏定义进行封装,所以操作寄存器的时候用如下方式处理:GPIOC->ODR = 0X0000;而不再像STM8一样直接写成GPIOC_ODR =0X0000;

STM32 DMA使用详解

DMA部分我用到的相对简单,当然,可能这是新东西,我暂时还用不到它的复杂功能吧.下面用问答的形式表达我的思路. DMA有什么用? 直接存储器存取用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输.无须CPU的干预,通过DMA数据可以快速地移动.这就节省了CPU的资源来做其他操作. 有多少个DMA资源? 有两个DMA控制器,DMA1有7个通道,DMA2有5个通道. 数据从什么地方送到什么地方? 外设到SRAM(I2C/UART等获取数据并送入SRAM): SRAM的两个区域之间: 外设

stm32 DMA配置

DMA就是将一个地址空间复制到另外一个地址空间.DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为RAM与I/O设备直接传送数据,使CPU的效率大大的提高了. stm一般有两个DMA控制器,DMA1有7通道.DMA2有5个通道. STM32 的 DMA 有以下一些特性:  ●每个通道都直接连接专用的硬件 DMA 请求,每个通道都同样支持软件触发. 这些功能通过软件来配置. ●在七个请求间的优先权可以通过软件编程设置(共有四级:很高.高.中等和低),

JAVASE02-Unit07: 基本IO操作 、 文本数据IO操作

基本IO操作 . 文本数据IO操作 java标准IO(input/output)操作 package day07; import java.io.FileOutputStream; import java.io.IOException; /** * java标准IO(input/output)操作 * 输入流InputStrean:用于从数据源读取数据到程序中 * 输出流OutputStream:用于将数据发送至目标 * * 流划分为:节点流,处理流 * 节点流:又叫做低级流,特点:数据源明确,

PIC18系列单片机I/O端口操作寄存器及应用

试验芯片:Microchip PIC 18F4550 集成开发环境:MPLAB IDE v8.53 编译器:Microchip C18 PIC18系列单片机是美国微芯公司(Microchip)8位单片机系列中的高档系列,其任一I/O引脚允许的最大灌电流或最大拉电流达25mA,可以直接驱动LED和继电器.PORTA.PORTB 和PORTE 的最大灌电流或最大拉电流总和为200mA,PORTC和PORTD的最大灌电流或最大拉电流总和为200mA,PORTF和PORTG的最大灌电流或最大拉电流总和为

STM32定时器的预装载寄存器与影子寄存器之间的关系【转】

首先转载:   STM32定时器的预装载寄存器与影子寄存器之间的关系 本文的说明依据STM32参考手册(RM0008)第10版:英文:http://www.st.com/stonline/products/literature/rm/13902.pdf中译文:http://www.stmicroelectronics.com.cn/stonline/mcu/images/STM32_RM_CH_V10_1.pdf 在STM32参考手册的第13.14章中,都有一张定时器的框图,下面是第14章中定时

外部SRAM实验,让STM32的外部SRAM操作跟内部SRAM一样(转)

源:外部SRAM实验,让STM32的外部SRAM操作跟内部SRAM一样 前几天看到开源电子论坛(openedv.com)有人在问这个问题,我特意去做了这个实验,这样用外部SRAM就跟用内部SRAM一样,不用自己去申请内存,也不用考虑什么内存地址,一切让编译器自己去解决. 废话不多说,我直接拿原子哥的战舰开发板库函数版的外部SRAM实验来修改.在库函数的system_stm32f10x.c这个初始化文件当中其实就已经有外部SRAM的初始化,我们只要增加“#define DATA_IN_ExtSRA

STM32 DMA简述

STM32 DMA简述 DMA (Direct Memory Access) 直接内存存储器,在做数据传输时能够大大减轻CPU的负担. DMA的作用 DMA提供了一个关于数据的高数传输通道,这个通道不占用CPU的资源.换句话说,通过DMA通道,你在传输大规模数据的时候CPU同时也能够去干其他事. 你可以控制DMA通道的接入口,灵活配置传输的数据源和目的地.以下几个是常用的DMA传输路径: 从外设到内存 从内存A区域传到内存B区域 从一个外设传输到另一个外设 从内存传输数据到外设 .... DMA