dma读nand_stm32 NAND闪存成功读取ID程序

#include "stm32f10x.h"

#include "stm32f10x_flash.h"

#define SET_CLE GPIO_SetBits(GPIOD, GPIO_Pin_6)

#define CLR_CLE GPIO_ResetBits(GPIOD, GPIO_Pin_6)

#define SET_ALE GPIO_SetBits(GPIOD, GPIO_Pin_5)

#define CLR_ALE GPIO_ResetBits(GPIOD, GPIO_Pin_5)

#define SET_CE GPIO_SetBits(GPIOD, GPIO_Pin_7)

#define CLR_CE GPIO_ResetBits(GPIOD, GPIO_Pin_7)

#define SET_WE GPIO_SetBits(GPIOD, GPIO_Pin_14)

#define CLR_WE GPIO_ResetBits(GPIOD, GPIO_Pin_14)

#define SET_RE GPIO_SetBits(GPIOD, GPIO_Pin_15)

#define CLR_RE GPIO_ResetBits(GPIOD, GPIO_Pin_15)

void mysysinit(void);//系统时钟初始

void my_USART_init(void);//初始化

void my_send_byte(unsigned char send_date); //发送一个字节

GPIO_InitTypeDef GPIO_InitStructure;

void READ_NAND_ID(void);

void delay_1us(uint32_t);

void my_NAND_INIT(void ); //nand flash 初始化

void wait_NAND_readay(void);

int main()

{

mysysinit();//RCC初始化,系统时钟设置72MHZ

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能APB2的GPIO_D时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);//使能APB2的GPIO_D时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//使能APB2的GPIO_B时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);//使能APB2的GPIO_E时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);//使能APB2的GPIO_E时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能APB1的USART2时钟

/* led*/

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9| GPIO_Pin_10| GPIO_Pin_11;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_Init(GPIOD, &GPIO_InitStructure);

/* 设置PB.5用于控制NAND的为上拉输入 */

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;

GPIO_Init(GPIOB, &GPIO_InitStructure);

my_USART_init();

wait_NAND_readay();

GPIO_SetBits(GPIOD, GPIO_Pin_8);

my_send_byte(0);

my_send_byte(1);

my_send_byte(2);

my_send_byte(3);

READ_NAND_ID();

while(1);

}

/*等待芯片不忙*/

void wait_NAND_readay()

{

uint8_t wait=0;//忙闲信号

//等待芯片不忙

do

{ wait=GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_5);//读取忙闲引脚

}

while(0x00==wait);

}

/*读取NAND闪存的ID序列号串口发送*/

void READ_NAND_ID()

{

uint8_t a=0,b=0,c=0,d=0;

/* 设置PD口用于控制NAND的为输出 */

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6| GPIO_Pin_7| GPIO_Pin_14| GPIO_Pin_15;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_Init(GPIOD, &GPIO_InitStructure);

/*设置PE口得低八位为输出*/

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1| GPIO_Pin_2| GPIO_Pin_3| GPIO_Pin_4|GPIO_Pin_7 | GPIO_Pin_6| GPIO_Pin_7;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_Init(GPIOE, &GPIO_InitStructure);

//delay_1us(1000000);

CLR_CE;//开启片选

SET_CLE;//命令锁存开启

CLR_WE;//写使能

CLR_ALE;//地址锁存关闭

SET_RE;//读关闭

GPIO_Write(GPIOE, 0x90); //读ID命令

SET_WE;//关闭写

CLR_CLE;

SET_ALE;

CLR_WE;

GPIO_Write(GPIOE, 0x00); //地址00

SET_WE;

/*设置PE口得低八位为输入*/

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1| GPIO_Pin_2| GPIO_Pin_3| GPIO_Pin_4|GPIO_Pin_7 | GPIO_Pin_6| GPIO_Pin_7;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;

GPIO_Init(GPIOE, &GPIO_InitStructure);

CLR_ALE; //注意啊,这里一定把他放在下面应为是有时间要求的;时序图TAR=15纳秒之后才是RE的操作;

//读出的结果是AD F1 80 1D ,2011年8月26日,与天津第四项目部宿舍

CLR_RE;

a=(GPIOE->IDR);

SET_RE;

CLR_RE;

b=(GPIOE->IDR);

SET_RE;

CLR_RE;

c=(GPIOE->IDR);

SET_RE;

CLR_RE;

d=(GPIOE->IDR);//delay_1us(1);

SET_RE;

SET_CE;//关闭片选

my_send_byte(a);

my_send_byte(b);

my_send_byte(c);

my_send_byte(d);

}

/********************

延时函数

形参:uint8_t time

功能:延时数值为time值

*********************/

void delay_1us(uint32_t time)

{   uint32_t b,c;

for(c=time;c;c--) //定时=time*3*333.6=time*1000.8ns

{

for(b=8;b;b--); //8*13.9*3= 333.6

}

}

/***********************************

发送一个字节函数通过串口

************************************/

void my_send_byte(unsigned char send_date )

{

while( (USART1->SR&0x00000080)!=0x80);//发送寄存器为空

USART1->DR=send_date;

}

/**********************************

初始化串口

**********************************/

void my_USART_init()

{

/*USART2的优先级设为5*/

NVIC->IP[37]=5;

/*开启38号中断即USART2,关闭其他所有外部的中断*/

NVIC->ISER[1]=0x00000020;

/*设置复用模式下的引脚模式为全双工:TX输出推挽复用,RX为输入上拉模式,速度50MHZ*/

GPIOA->CRH=0x000008b0;

/* 1.开启USART,

*

*/

USART1->CR1=0x2000;

/* 1.关闭局域网模式

* 2.1个停止位

* 3.CK引脚禁能

*/

USART1->CR2=0;

/* 1.关闭调制解调模式

* 2.关闭DMA模式

* 3.关闭智能卡、红外模式

*   4.关闭错误中断

*/

USART1->CR3=0;

/*     波特率设置

2011年8月11日

王均伟

天津第四项目部宿舍

BRR中的第四位(DIV_Fraction)作为小数,高12位(DIV_MANtissa)作为整数部分,

1,根据公式:波特率=fck/16*usardiv,其中usardivBRR寄存器的值,所以变形得:USARDIV=fck/16*波特率

2.算出来BRR寄存器的值后就要把这个值变成16进制数据写入BRR寄存器中,

遵循以下规则:

小数部分*16=DIV_Fraction或者取近似的值

整数部分直接=DIV_MANtissa

3.把这个16进制值写入BRR寄存器

例如我要算波特率设成9600bps的BRR寄存器值,

1.先求USARDIV=36000000/16*9600=234.375

2.换成十六进制:DIV_Fraction=16*0.375=0x6

DIV_MANtissa=234=0xea

3.组合并写入寄存器

USART2->BRR=0x0ea6;值得注意的是这里是16位半字操作,所以不要以为是32位。

*/

USART1->BRR=0x0ea6;

/* 1.开启USART

* 2.开启接收完毕中断

* 3.开启发送功能

*   4.开启接收功能

*/

USART1->CR1=0x202c;

}

void mysysinit()//系统初始化程序

{

ErrorStatus HSEStartUpStatus;//说明标志位

RCC_DeInit();//所有外设全部缺省设置

/* Enable HSE */

RCC_HSEConfig(RCC_HSE_ON);

/* Wait till HSE is ready and if Time out is reached exit */

HSEStartUpStatus = RCC_WaitForHSEStartUp();

if(HSEStartUpStatus == SUCCESS)//启动成功

{

/*这两条FLASH指令必须加上,不知为啥?不加上就运行几秒后出错,参照系统初始化*/

/* Enable The Prefetch Buffer */

FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);//FLASH缓存开启

/* Configure the Latency cycle: Set 2 Latency cycles */

FLASH_SetLatency(FLASH_Latency_2);  //设置FLASH这些位表示SYSCLK(系统时钟)周期与闪存访问时间的比例,为010:两个等待状态,当 48MHz < SYSCLK ≤ 72MHz

/* Set PLL clock output to 72MHz using HSE (8MHz) as entry clock */

RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);//外部时钟为8M,PLL的输入时钟=8MHZ,倍频系数9,

/* Configure HCLK such as HCLK = SYSCLK */

RCC_HCLKConfig(RCC_SYSCLK_Div1);//设置了啦AHB分频器的分频系数=1,即HCLK=SYSCLK=72MHZ

/* Configure PCLK1 such as PCLK1 = HCLK/2 */

RCC_PCLK1Config(RCC_HCLK_Div2);//设置了APB1外设的时钟频率最大是36M这里是APB1的分频器设为2,PCLK1=HCLK/2=72/2=36MHZ正好是最大值

/* Configure PCLK2 such as PCLK2 = HCLK */

RCC_PCLK2Config(RCC_HCLK_Div1);//设置PLCK2=HCLK=72MHZ,的APB2分频器=1

/* Select the PLL as system clock source */

RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);//设置了SYSCLK的提供者为PLL,频率由上面算出=72MHZ

/* disable PLL Ready interrupt */

RCC_ITConfig(RCC_IT_PLLRDY, DISABLE);//PLL中断关闭

/* disable PLL Ready interrupt */

RCC_ITConfig(RCC_IT_HSERDY,DISABLE);//HSE中断关闭

/* disable PLL Ready interrupt */

RCC_ITConfig(RCC_IT_HSIRDY, DISABLE); //HSI中断关闭

/* disable PLL Ready interrupt */

RCC_ITConfig(RCC_IT_LSERDY, DISABLE); //LSE中断关闭

/* disable PLL Ready interrupt */

RCC_ITConfig(RCC_IT_LSIRDY, DISABLE); //LSI中断关闭

/* PLL clock divided by 1.5 used as USB clock source */

RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5);//设置USB的时钟为=72、1.5=48mhz

/* Configure ADCCLK such as ADCCLK = PCLK2/2 */

RCC_ADCCLKConfig(RCC_PCLK2_Div2);//设置ADC时钟=PCLK2/2= 36MHZ

/* disable the LSE */

RCC_LSEConfig(RCC_LSE_OFF);//外部低速晶振关闭

/*DISable the RTC clock */

RCC_RTCCLKCmd(DISABLE);

/* DISable the Clock Security System */

RCC_ClockSecuritySystemCmd(DISABLE);

/* Enable the PLL */

RCC_PLLCmd(ENABLE);//使能PLL

/* PLL ans system clock config */

}

else

{

/* Add here some code to deal with this error */

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32中,DMA的双缓冲模式可以通过配置DMA的通道控制寄存器来实现。下面是一个示例代码,可以帮助你理解如何使用STM32DMA双缓冲模式。 首先,需要定义两个缓冲区,用于DMA写操作。在本示例中,我们假设缓冲区大小为16字节。 ```c #define BUFFER_SIZE 16 uint8_t buffer1[BUFFER_SIZE]; uint8_t buffer2[BUFFER_SIZE]; ``` 然后,需要配置DMA通道的控制寄存器。在本示例中,我们使用DMA1通道1,并启用双缓冲模式。 ```c DMA_HandleTypeDef hdma; hdma.Instance = DMA1_Channel1; hdma.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma.Init.PeriphInc = DMA_PINC_DISABLE; hdma.Init.MemInc = DMA_MINC_ENABLE; hdma.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma.Init.Mode = DMA_CIRCULAR; hdma.Init.Priority = DMA_PRIORITY_HIGH; hdma.Init.FIFOMode = DMA_FIFOMODE_DISABLE; hdma.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; hdma.Init.MemBurst = DMA_MBURST_SINGLE; hdma.Init.PeriphBurst = DMA_PBURST_SINGLE; HAL_DMA_Init(&hdma); __HAL_DMA_DISABLE(&hdma); hdma.Instance->CR |= DMA_SxCR_DBM; ``` 接下来,需要启动DMA传输。 ```c HAL_DMA_Start(&hdma, (uint32_t)&peripheral_device, (uint32_t)buffer1, BUFFER_SIZE); ``` 在DMA传输期间,当缓冲区1已经被填满时,DMA会自动切换到缓冲区2进行数据传输。当缓冲区2也被填满时,DMA会再次切换回缓冲区1。 当需要读取DMA传输的数据时,可以通过检查DMA传输期间使用的缓冲区来获取传输的数据。 ```c uint8_t* buffer = (hdma.Instance->CR & DMA_SxCR_CT) ? buffer2 : buffer1; ``` 最后,在传输完成后,需要停止DMA传输并释放DMA通道。 ```c HAL_DMA_Stop(&hdma); HAL_DMA_DeInit(&hdma); ``` 以上就是一个基本的DMA双缓冲模式的示例代码。需要注意的是,在使用DMA双缓冲模式时,需要保证缓冲区大小足够大,以避免数据溢出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值