1MM32SPIN0230的USART简介
MM32SPIN0230通用同步/异步收发器(USART)可以灵活地与外部设备进行全双工数据交换。通过内置波特率(包含整数及小数设定)发生器, USART 可以支持宽范围的波特率。
USART 支持异步模式(UART)、同步模式。其中 UART 支持单线半双工通信, UART 和同步模式支持调制解调器(CTS/RTS)操作。
2MM32SPIN0230的USART功能框图
USART 的功能框图如下图1所示,由寄存器相关的控制单元、收发数据控制器、时钟控制器、硬件流控制单元以及引脚控制逻辑单元组成。
图1 MM32SPIN0230 USART功能框图
3USART的同步模式
通过配置,USART_CR1.SAS 位为‘1’来使能同步模式(时钟引脚功能将同时有效)。
在同步模式下, USART_CR3.HDSEL 位应配置为‘0’。
同步模式支持主模式和从模式:主模式时使用内部波特率生成器生成的时钟,同时输出时钟;从模式时由 SCLK 引脚输入时钟。USART 在同步模式下,能与 SPI 实现数据通信(此时,用户应配置 SPI 与USART 的时钟极性、时钟相位为一致)。
4USART的时钟
USART的时钟挂载在APB1总线上,由APB1总线提供工作时钟,以配置 USART_CR2.CLKEN 位为‘1’来使能时钟引脚功能, 同时根据 USART_CR3.CKINE 位配置来选择使用内部波特率时钟或从 SCLK 引脚输入时钟,以进行数据通信。
当选择内部波特率时钟时,可通过 SCLK 引脚输出同步时钟。
1 帧数据的收发包含 8 个时钟脉冲。
当 RE 和 TE 都为‘0’, 时钟输出会停止, 并固定在 USART_CR2.CPOL 配置的电平。
通过配置 USART_CR2.CPOL 位选择时钟极性。
通过配置 USART_CR2.CPHA 位选择外部时钟相位。
5USART时钟同步功能
SCLK 引脚作为发送器的时钟输出时,仅在数据段输出时钟,一帧数据输出 8 个时钟脉冲,最后一位发送完后,通信线保持最后一位的值,时钟输出固定在高电平或低电平(由 CPOL 位决定)。
USART 接收器在同步模式下的工作方式与异步模式下不同。如果 RE=1,则数据在 SCLK 变化边沿上采样(上升或下降沿,取决于 CPOL 和 CPHA 位配置情况),而不会进行任何过采样。此时必须确保足够的建立时间和保持时间,以符合时序要求(类同于 SPI 协议)。
内部时钟源时,内部波特率生成器生成的波特率计算公式为:
其中通信波特率的单为 MBps;PCLK 为内部时钟源的频率;MFD 为 波特率寄存器 USART_BRR 中整数分频(注意, 在同步模式下应配置 MFD ≥ 2, 且小数分频 FFD 无效, 用户应配置 FFD[3:0] 位为4’h0)。
使用内部时钟源且 MFD=2 时,同步模式的最高波特率为 PCLK/8(MBps)。
外部时钟源时,要求外部输入时钟的最大频率为 PCLK/8( MHz),此时最高波特率也为 PCLK/8(MBps)。
6USART的特性描述
如下图2所示为USART的数据帧类型示意图,当USART用作同步通信时,可通过配置同步时钟引脚即USART_SCK引脚的时钟极性和时钟相位实现SPI功能的通信。此时没有起始位,校验位以及停止位功能,仅支持8位。通过配置时钟极性CPOL和时钟相位CPHA可以实现基于USART的SPI通信的工作模式0-3。
图2 MM32SPIN0230 USART数据帧类型示意图
7USART同步模式实现SPI通信的配置步骤
MM32SPIN0230有一路USART1,USART1同步模式实现SPI通信的配置步骤如下所示。
使能USART1的时钟和用作USART1的GPIO时钟
配置GPIO复用为USART1功能
配置一路普通GPIO为推挽输出模式用于USART同步通信的CS引脚
配置 USART1_CR1.SAS 位为‘1’来使能同步模式(时钟引脚功能将同时有效)
配置 USART1_CR1.MLS 位为‘0’或 为‘1’来选择数据格式为LSB或MSB
配置 USART1_CR3.HDSEL位为‘0’来选择数据通信为全双工模式
配置 USART1_CR2.CPOL位为‘0’ 或 为‘1’设置时钟空闲时为低电平或高电平
配置 USART1_CR2.CPHA位为‘0’ 或 为‘1’设置在时钟第一个变化沿捕获数据或在时钟第二个变化沿捕获数据
配置USART1_BRR波特率寄存器小数分频FFD[3:0]为0(USART同步模式,波特率小数分频无效)
配置USART1同步模式波特率,USART1_BRR波特率寄存器整数分频MFD[15:0],需配置MFD>=2
使能USART1接收和发送中断以及NVIC中断优先级(如有使用到USART接收和发送中断功能)
使能USART1功能
编写应用层USART1同步通信模式下数据接收、数据发送函数以及中断处理接收和中断发送函数。(如使能了接收和发送中断功能)
8USART同步模式实现SPI通信
读写W25Q32存储器
根据以上配置步骤USART1同步模式实现SPI通信的配置步骤,使用MM32SPIN0230的库函数配置USART1为同步模式主机功能实现SPI通信读写W25Q32 Flash存储器,分别配置GPIO PA11复用为USART1_TX功能,PA12复用为USART1_RX功能,PB2复用为USART1_SCLK功能(注:USART1用作同步模式主机功能PA11 USART1_TX当做SPI_MOSI引脚使用,PA12 USART1_RX当做SPI_MISO引脚使用,PB2 USART1_SCLK当做SPI_SCL使用)并配置GPIO PB4为推挽输出模式当做SPI_CSS引脚使用。
USART1同步通信模式实现SPI通信的初始化代码如下所示:
#defineSPI_FLASH_CS_H()GPIO_WriteBit(GPIOB,GPIO_Pin_4,Bit_SET) #defineSPI_FLASH_CS_L()GPIO_WriteBit(GPIOB,GPIO_Pin_4,Bit_RESET) uint16_tDeviceID=0;/*W25Q64DeviceID*/ uint32_tJEDEC_ID=0;/*W25Q64JEDECID*/ voidUSART_Configure(uint32_tBaudrate) { GPIO_InitTypeDefGPIO_InitStruct; NVIC_InitTypeDefNVIC_InitStruct; RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART1,ENABLE); USART_SyncMasterConfig(USART1,USART_Clock_Idle_Low,USART_Clock_Phase_1Edge,Baudrate);/*USARTInitconfigureSPIMode0*/ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB,ENABLE); GPIO_PinAFConfig(GPIOA,GPIO_PinSource11,GPIO_AF_5);/*PA11AFUSART_TXforSPI_MOSIfunction*/ GPIO_PinAFConfig(GPIOA,GPIO_PinSource12,GPIO_AF_5);/*PA12AFUSART_RXforSPI_MISOfunction*/ GPIO_PinAFConfig(GPIOB,GPIO_PinSource2,GPIO_AF_6);/*PB2AFUSART_SCLKforSPI_SCLKfunction*/ GPIO_StructInit(&GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin=GPIO_Pin_4; GPIO_InitStruct.GPIO_Speed=GPIO_Speed_High; GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;/*PB4forSPI_CSSfunction*/ GPIO_Init(GPIOB,&GPIO_InitStruct); SPI_FLASH_CS_H();/*SetPB4forSPI_CSSHighleve*/ GPIO_StructInit(&GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin=GPIO_Pin_11; GPIO_InitStruct.GPIO_Speed=GPIO_Speed_High; GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP; GPIO_Init(GPIOA,&GPIO_InitStruct); GPIO_StructInit(&GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin=GPIO_Pin_12; GPIO_InitStruct.GPIO_Speed=GPIO_Speed_High; GPIO_InitStruct.GPIO_Mode=GPIO_Mode_FLOATING; GPIO_Init(GPIOA,&GPIO_InitStruct); GPIO_StructInit(&GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin=GPIO_Pin_2; GPIO_InitStruct.GPIO_Speed=GPIO_Speed_High; GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP; GPIO_Init(GPIOB,&GPIO_InitStruct); NVIC_InitStruct.NVIC_IRQChannel=USART1_IRQn; NVIC_InitStruct.NVIC_IRQChannelPriority=0x01; NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE; NVIC_Init(&NVIC_InitStruct); USART_Cmd(USART1,ENABLE); }
USART1同步通信模式中断接收数据,代码如下所示:
voidUSART_Synchronous_RxData_Interrupt(uint8_t*Buffer,uint8_tLength) { uint8_ti=0; for(i=0;i< Length; i++) { USART_RxStruct.Buffer[i] = 0; USART_TxStruct.Buffer[i] = 0; } USART_RxStruct.Length = Length; USART_RxStruct.CurrentCount = 0; USART_RxStruct.CompleteFlag = 0; USART_TxStruct.Length = Length; USART_TxStruct.CurrentCount = 0; USART_TxStruct.CompleteFlag = 0; USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); USART_ITConfig(USART1, USART_IT_TXE, ENABLE); while (0 == USART_TxStruct.CompleteFlag) { } while (0 == USART_RxStruct.CompleteFlag) { } for (i = 0; i < Length; i++) { Buffer[i] = USART_RxStruct.Buffer[i]; } }
USART1同步通信模式中断发送数据,代码如下所示:
voidUSART_Synchronous_TxData_Interrupt(uint8_t*Buffer,uint8_tLength) { uint8_ti=0; for(i=0;i< Length; i++) { USART_RxStruct.Buffer[i] = 0; USART_TxStruct.Buffer[i] = Buffer[i]; } USART_RxStruct.Length = Length; USART_RxStruct.CurrentCount = 0; USART_RxStruct.CompleteFlag = 0; USART_TxStruct.Length = Length; USART_TxStruct.CurrentCount = 0; USART_TxStruct.CompleteFlag = 0; USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); USART_ITConfig(USART1, USART_IT_TXE, ENABLE); while (0 == USART_TxStruct.CompleteFlag) { } while (0 == USART_RxStruct.CompleteFlag) { } }
USART1同步通信模式读SPI Flash,代码如下所示:
voidSPI_FLASH_RxBuffer(uint8_t*Buffer,uint8_tLength) { if(Length) { USART_Synchronous_RxData_Interrupt(Buffer,Length); } }
USART1同步通信模式写SPI Flash,代码如下所示:
voidSPI_FLASH_TxBuffer(uint8_t*Buffer,uint8_tLength) { if(Length) { USART_Synchronous_TxData_Interrupt(Buffer,Length); } }
USART1同步通信模式处理中断接收和发送命令和读写数据,即读写SPI Flash,代码如下所示:
voidUSART1_IRQHandler(void) { uint8_tRxData=0; if(RESET!=USART_GetITStatus(USART1,USART_IT_RXNE)) { RxData=USART_ReceiveData(USART1); if(0==USART_RxStruct.CompleteFlag) { USART_RxStruct.Buffer[USART_RxStruct.CurrentCount++]=RxData; if(USART_RxStruct.CurrentCount==USART_RxStruct.Length) { USART_RxStruct.CompleteFlag=1; USART_ITConfig(USART1,USART_IT_RXNE,DISABLE); USART_ITConfig(USART1,USART_IT_TXE,DISABLE); } } } if(RESET!=USART_GetITStatus(USART1,USART_IT_TXE)) { if(0==USART_TxStruct.CompleteFlag) { USART_SendData(USART1,USART_TxStruct.Buffer[USART_TxStruct.CurrentCount++]); if(USART_TxStruct.CurrentCount==USART_TxStruct.Length) { USART_TxStruct.CompleteFlag=1; } } } }
USART1同步通信模式SPI Flash写使能,代码如下所示:
voidSPI_FLASH_WriteEnable(void) { uint8_tCommand=0x06; SPI_FLASH_CS_L(); SPI_FLASH_TxBuffer(&Command,0x01); SPI_FLASH_CS_H(); }
USART1同步通信模式判断SPI Flash是否处于总线忙转态,代码如下所示:
voidSPI_FLASH_WaitBusy(void) { uint8_tStatus=0; uint8_tCommand[2]= { 0x05,0xFF }; uint32_tTimeout=0; do { SPI_FLASH_CS_L(); SPI_FLASH_TxBuffer(Command,0x02); SPI_FLASH_RxBuffer(&Status,0x01); SPI_FLASH_CS_H(); if(Timeout++>0xFFFF) { break; } } while(Status&0x01); }
USART1同步通信模式读SPI Flash DeviceID,代码如下所示:
voidSPI_FLASH_ReadDeviceID(void) { uint8_tCommand[4]= { 0x90,0xFF,0xFF,0x00 }; uint8_tBuffer[2]; SPI_FLASH_CS_L(); SPI_FLASH_TxBuffer(Command,0x04); SPI_FLASH_RxBuffer(Buffer,0x02); SPI_FLASH_CS_H(); DeviceID=Buffer[0]; DeviceID<<= 8; DeviceID |= Buffer[1]; }
USART1同步通信模式读SPI Flash JEDEC ID,代码如下所示:
voidSPI_FLASH_ReadJEDEC_ID(void) { uint8_tCommand=0x9F; uint8_tBuffer[3]; SPI_FLASH_CS_L(); SPI_FLASH_TxBuffer(&Command,0x01); SPI_FLASH_RxBuffer(Buffer,0x03); SPI_FLASH_CS_H(); JEDEC_ID=Buffer[0]; JEDEC_ID<<= 8; JEDEC_ID |= Buffer[1]; JEDEC_ID <<= 8; JEDEC_ID |= Buffer[2]; }
USART1同步通信模式SPI Flash 扇区擦除,代码如下所示:
voidSPI_FLASH_SectorErase(uint16_tIndex) { uint8_tCommand[4]= { 0x20,0x00,0x00,0x00 }; uint32_tAddress=Index*4*1024; Command[1]=(uint8_t)((Address>>16)&0x000000FF); Command[2]=(uint8_t)((Address>>8)&0x000000FF); Command[3]=(uint8_t)((Address>>0)&0x000000FF); SPI_FLASH_WriteEnable(); SPI_FLASH_CS_L(); SPI_FLASH_TxBuffer(Command,4); SPI_FLASH_CS_H(); SPI_FLASH_WaitBusy(); }
USART1同步通信模式快速读SPI Flash,代码如下所示:
voidSPI_FLASH_FastRead(uint32_tAddress,uint8_t*Buffer,uint32_tLength) { uint8_tCommand[5]= { 0x0B,0x00,0x00,0x00,0xFF }; Command[1]=(uint8_t)((Address>>16)&0x000000FF); Command[2]=(uint8_t)((Address>>8)&0x000000FF); Command[3]=(uint8_t)((Address>>0)&0x000000FF); SPI_FLASH_CS_L(); SPI_FLASH_TxBuffer(Command,0x05); SPI_FLASH_RxBuffer(Buffer,Length); SPI_FLASH_CS_H(); }
USART1同步通信模式页编程SPI Flash,代码如下所示:
voidSPI_FLASH_PageProgram(uint32_tAddress,uint8_t*Buffer,uint32_tLength) { uint8_tCommand[4]= { 0x02,0x00,0x00,0x00 }; Command[1]=(uint8_t)((Address>>16)&0x000000FF); Command[2]=(uint8_t)((Address>>8)&0x000000FF); Command[3]=(uint8_t)((Address>>0)&0x000000FF); SPI_FLASH_WriteEnable(); SPI_FLASH_CS_L(); SPI_FLASH_TxBuffer(Command,0x04); SPI_FLASH_TxBuffer(Buffer,Length); SPI_FLASH_CS_H(); SPI_FLASH_WaitBusy(); }
验证USART1同步通信模式读写W25Q32 SPI Flash,本实例在MDK Keil环境下编译验演示,在main函数中调用读写W25Q32 SPI Flash的函数,代码如下所示:
intmain(void) { uint8_ti=0; uint8_tEraseBuffer[100],WriteBuffer[100],ReadBuffer[100]; USART_RxStruct.CompleteFlag=0; USART_TxStruct.CompleteFlag=1; USART_Configure(8000000);/*ConfigureUSARTRead/writeSPIFlashbaudrate8M*/ SPI_FLASH_ReadDeviceID(); SPI_FLASH_ReadJEDEC_ID(); SPI_FLASH_SectorErase(0);/*USARTerasestheSPIFlashsector*/ SPI_FLASH_FastRead(0,EraseBuffer,100); for(i=0;i< 100; i++) { WriteBuffer[i] = i; } SPI_FLASH_PageProgram(0, WriteBuffer, 100); /* USART page programming SPI Flash writes 100 bytes of data */ SPI_FLASH_FastRead(0, ReadBuffer, 100); /* The USART reads 100 bytes of data written to the SPI Flash */ PLATFORM_DeInitUSART1(); PLATFORM_InitConsole(115200); printf(" "); printf(" SPI Flash DeviceID : 0x%04x", DeviceID); printf(" SPI Flash JEDEC ID : 0x%06x", JEDEC_ID); printf(" SPI FLASH Sector Erase..."); printf(" SPI FLASH Read..."); for (i = 0; i < 100; i++) { if (0 == (i % 10)) { printf(" "); } printf("0x%02x ", EraseBuffer[i]); } printf(" SPI FLASH Page Program..."); printf(" SPI FLASH Read..."); for (i = 0; i < 100; i++) { if (0 == (i % 10)) { printf(" "); } printf("0x%02x ", ReadBuffer[i]); } while (1) { } }
使用MM32-LINK Mini调试下载工具连接MM32SPIN0230 MiniBoard,板子USB口连接USB串口工具连接到电脑端,打开串口调试助手,并配置串口波特率为115200,按快捷键F7编译工程,编译成功后按快捷键F8下载程序到MM32SPIN0230 MiniBoard,如下图3所示,串口调试助手分别打印输出了W25Q32 SPI Flash的DeviceID和JEDEC ID,USART1同步通信模式扇区擦除W25Q32 SPI Flash数据后读出的100字节0xFF数据(说明擦除成功),以及USART1同步通信模式写入到W25Q32 SPI Flash中的0-99共100字节数据(每行10字节,共10行),读出了写入的0-99共100字节数据,写入和读出的数据一致即0-99对应十六进制为0x00-0x63。
图3 测试结果
审核编辑:汤梓红
-
FlaSh
+关注
关注
10文章
1634浏览量
148007 -
存储器
+关注
关注
38文章
7490浏览量
163819 -
SPI
+关注
关注
17文章
1706浏览量
91565 -
uart
+关注
关注
22文章
1235浏览量
101383 -
异步收发器
+关注
关注
0文章
36浏览量
10848
发布评论请先 登录
相关推荐
评论