GD32F470如何搭建BSP驱动框架(连载)
本帖最后由 caizhiwei 于 2024-6-2 08:58 编辑#申请原创# #技术资源#@21小跑堂
各位二姨家网友好。
前段时间在做一个GD32F470为核心的嵌入式项目,一开始想套用STM32的代码,后来发现简单的IO控制,uart是没啥问题的,复杂的外设ADC+DMA, USB_Device虚拟串口等,会出现bug,后来咨询原厂FAE,他们给出的答案是GD芯片虽然兼容ST,但是不是100%兼容,内部有改进和创新,推荐使用GD官网下载的寄存器驱动库。
寄存器库虽然可以用,但是还要写不少接口函数,所以打算自己实现一个bsp层,分享给网友。
代码分层框架如下(橙色的外设就是要实现的bsp层):
采用IAR IDE
先说说flash驱动吧,GD32F470 支持扇区内的按页擦除(每一页是4kb),这样给fatfs移植提供了方便。
/*对于1MB flash容量的GD32F470VGT来说, 没有定义 8,9,10,11扇区,从而软件是兼容1~ 3MB型号的*/
//对于GD32F4xx,使用了两片闪存;前1024KB容量在第0片闪存(bank0)中
//后1024kb的容量在第1片闪存(bank1)中
// 每个扇区中,以4KB字节大小为一页,Flash可以按页(最小单位)擦除。
#ifndef __BSP_FLASH_H__
#define __BSP_FLASH_H__
#include "gd32f4xx.h"
#include <stdbool.h>
#include <stdio.h>
#include "includes.h"
/* flash相关宏定义 */
/*对于1MB flash容量的GD32F470VGT来说, 没有定义 8,9,10,11扇区,从而软件是兼容1~ 3MB型号的*/
//对于GD32F4xx,使用了两片闪存;前1024KB容量在第0片闪存(bank0)中
//后1024kb的容量在第1片闪存(bank1)中
// 每个扇区中,以4KB字节大小为一页,Flash可以按页(最小单位)擦除
#define ADDR_FLASH_SECTOR_0 ((uint32_t)0x08000000) /* Base @ of Sector 0, / */
#define ADDR_FLASH_SECTOR_1 ((uint32_t)0x08004000) /* Base @ of Sector 1, 16 Kbytes */
#define ADDR_FLASH_SECTOR_2 ((uint32_t)0x08008000) /* Base @ of Sector 2, 16 Kbytes */
#define ADDR_FLASH_SECTOR_3 ((uint32_t)0x0800C000) /* Base @ of Sector 3, 16 Kbytes */
#define ADDR_FLASH_SECTOR_4 ((uint32_t)0x08010000) /* Base @ of Sector 4, 64 Kbytes */
#define ADDR_FLASH_SECTOR_5 ((uint32_t)0x08020000) /* Base @ of Sector 5, 128 Kbytes */
#define ADDR_FLASH_SECTOR_6 ((uint32_t)0x08040000) /* Base @ of Sector 6, 128 Kbytes */
#define ADDR_FLASH_SECTOR_7 ((uint32_t)0x08060000) /* Base @ of Sector 7, 128 Kbytes */
#define ADDR_FLASH_SECTOR_8 ((uint32_t)0x08080000) /* Base @ of Sector 8, 128 Kbytes */
#define ADDR_FLASH_SECTOR_9 ((uint32_t)0x080A0000) /* Base @ of Sector 9, 128 Kbytes */
#define ADDR_FLASH_SECTOR_10 ((uint32_t)0x080C0000) /* Base @ of Sector 10, 128 Kbytes */
#define ADDR_FLASH_SECTOR_11 ((uint32_t)0x080E0000) /* Base @ of Sector 11, 128 Kbytes */
/* end of 1024KB here */
#define ADDR_FLASH_SECTOR_12 ((uint32_t)0x08100000) /* Base @ of Sector 12, 16 Kbytes */
/*
....13 ~ 22 add here
*/
#define ADDR_FLASH_SECTOR_23 ((uint32_t)0x081E0000) /* Base @ of Sector 23, 128 Kbytes */
#define ADDR_FLASH_Bank0_START ((uint32_t)0x08000000)
#define ADDR_FLASH_Bank1_START ((uint32_t)0x08100000)
#define FMC_PAGE_SIZE((uint32_t)0x1000) /*4kb*/
/**
* @{扇区号}
*/
#define FLASH_Sector_0 ((uint16_t)0x0000) /*!< Sector Number 0 */
#define FLASH_Sector_1 ((uint16_t)0x0008) /*!< Sector Number 1 */
#define FLASH_Sector_2 ((uint16_t)0x0010) /*!< Sector Number 2 */
#define FLASH_Sector_3 ((uint16_t)0x0018) /*!< Sector Number 3 */
#define FLASH_Sector_4 ((uint16_t)0x0020) /*!< Sector Number 4 */
#define FLASH_Sector_5 ((uint16_t)0x0028) /*!< Sector Number 5 */
#define FLASH_Sector_6 ((uint16_t)0x0030) /*!< Sector Number 6 */
#define FLASH_Sector_7 ((uint16_t)0x0038) /*!< Sector Number 7 */
#define FLASH_Sector_8 ((uint16_t)0x0040) /*!< Sector Number 8 */
#define FLASH_Sector_9 ((uint16_t)0x0048) /*!< Sector Number 9 */
#define FLASH_Sector_10 ((uint16_t)0x0050) /*!< Sector Number 10*/
#define FLASH_Sector_11 ((uint16_t)0x0058) /*!< Sector Number 11*/
#define FLASH_Sector_12 ((uint16_t)0x0080) /*!< Sector Number 12*/
#define FLASH_Sector_13 ((uint16_t)0x0088) /*!< Sector Number 13*/
#define FLASH_Sector_14 ((uint16_t)0x0090) /*!< Sector Number 14*/
#define FLASH_Sector_15 ((uint16_t)0x0098) /*!< Sector Number 15*/
#define FLASH_Sector_16 ((uint16_t)0x00A0) /*!< Sector Number 16*/
#define FLASH_Sector_17 ((uint16_t)0x00A8) /*!< Sector Number 17*/
#define FLASH_Sector_18 ((uint16_t)0x00B0) /*!< Sector Number 18*/
#define FLASH_Sector_19 ((uint16_t)0x00B8) /*!< Sector Number 19*/
#define FLASH_Sector_20 ((uint16_t)0x00C0) /*!< Sector Number 20*/
#define FLASH_Sector_21 ((uint16_t)0x00C8) /*!< Sector Number 21*/
#define FLASH_Sector_22 ((uint16_t)0x00D0) /*!< Sector Number 22*/
#define FLASH_Sector_23 ((uint16_t)0x00D8) /*!< Sector Number 23*/
typedef union
{
struct
{
uint8_t data1;
uint8_t data2;
uint8_t data3;
uint8_t data4;
}bf;
uint32_t data;
}fmc_data_t;
/* FMC sector information */
typedef struct
{
uint32_t sector_name; /*!< the name of the sector */
uint32_t sector_num; /*!< the number of the sector */
uint32_t sector_size; /*!< the size of the sector */
uint32_t sector_start_addr; /*!< the start address of the sector */
uint32_t sector_end_addr; /*!< the end address of the sector */
} fmc_sector_info_struct;
// 根据固件大小,计算出需要擦除的扇区
/* sector size */
#define SIZE_16KB ((uint32_t)0x00004000U) /*!< size of 16KB*/
#define SIZE_64KB ((uint32_t)0x00010000U) /*!< size of 64KB*/
#define SIZE_128KB ((uint32_t)0x00020000U) /*!< size of 128KB*/
#define SIZE_256KB ((uint32_t)0x00040000U) /*!< size of 256KB*/
/* FMC BANK address */
#define FMC_START_ADDRESS FLASH_BASE /*!< FMC start address */
#define FMC_BANK0_START_ADDRESS FMC_START_ADDRESS /*!< FMC BANK0 start address */
#define FMC_BANK1_START_ADDRESS ((uint32_t)0x08100000U) /*!< FMC BANK1 start address (1MB)*/
#define FMC_SIZE (*(uint16_t *)0x1FFF7A22U) /*!< FMC SIZE,存储在Flash中 */
#define FMC_END_ADDRESS (FLASH_BASE + (FMC_SIZE * 1024) - 1) /*!< FMC end address */
#define FMC_MAX_END_ADDRESS ((uint32_t)0x08300000U) /*!< FMC maximum end address(3MB) */
/* FMC error message */
#define FMC_WRONG_SECTOR_NAME ((uint32_t)0xFFFFFFFFU) /*!< wrong sector name*/
#define FMC_WRONG_SECTOR_NUM ((uint32_t)0xFFFFFFFFU) /*!< wrong sector number*/
#define FMC_INVALID_SIZE ((uint32_t)0xFFFFFFFFU) /*!< invalid sector size*/
#define FMC_INVALID_ADDR ((uint32_t)0xFFFFFFFFU) /*!< invalid sector address*/
ErrStatus BSP_fmc_erase_sectors(uint32_t sec_num, int sec_count);
void BSP_fmc_write_Word_NoCheck(uint32_t address, uint32_t length, uint32_t* data_32);
void BSP_fmc_read_Wrod(uint32_t address, uint16_t length, uint32_t* Outbuff);
/*页擦除*/
void BSP_fmc_erase_page(uint32_t sector_addr, int index);
void BSP_fmc_erase_multi_pages(uint32_t sector_addr, int start_page_index, int page_num);
bool BSP_fmc_sectors_is_blank_Check(uint32_t address);
bool BSP_fmc_page_is_blank_Check(uint32_t address);
// bank擦除
void BSP_fmc_erase_bank1(void);
#endif
再看看bsp_flash.c 中我们要实现的接口函数:
#include "bsp_flash.h"
const uint16_t FlashSec_Tab =
{
{0,FLASH_Sector_0},
{1,FLASH_Sector_1},
{2,FLASH_Sector_2},
{3,FLASH_Sector_3},
{4,FLASH_Sector_4},
{5,FLASH_Sector_5},
{6,FLASH_Sector_6},
{7,FLASH_Sector_7},
{8,FLASH_Sector_8},
{9,FLASH_Sector_9},
{10,FLASH_Sector_10},
{11,FLASH_Sector_11},
{12,FLASH_Sector_12},
{13,FLASH_Sector_13},
{14,FLASH_Sector_14},
{15,FLASH_Sector_15},
{16,FLASH_Sector_16},
{17,FLASH_Sector_17},
{18,FLASH_Sector_18},
{19,FLASH_Sector_19},
{20,FLASH_Sector_20},
{21,FLASH_Sector_21},
{22,FLASH_Sector_22},
{23,FLASH_Sector_23},
};
static uint8_t Fmc_get_Sector_index( int sector_num)
{
uint8_t index = 0;
for(int i = 0; i < 24; i++)
{
if(sector_num == FlashSec_Tab)
{
index = i;
break;
}
}
return index;
}
/*!
\brief 连续擦除多个扇区
\paramsec_num 起始扇区号( FLASH_Sector_0 ~ FLASH_Sector_23)
\paramsec_count 扇区数量
\retval none
*/
ErrStatus BSP_fmc_erase_sectors(uint32_t sec_num, int sec_count)
{
uint8_t index = 0;
fmc_unlock();
/* clear pending flags */
fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_OPERR | FMC_FLAG_WPERR\
| FMC_FLAG_PGMERR | FMC_FLAG_PGSERR);
index = Fmc_get_Sector_index( sec_num );
for(int i = 0; i < sec_count; i++)
{
fmc_sector_erase(CTL_SN(index + i));
//printf("Erase sector index = %d!\r\n", (index+i));
}
/* lock the flash program erase controller */
fmc_lock();
return SUCCESS;
}
/********************************************************************
\brief 从address 起始地址处 连续读出length个字到 Outbuff中,
\param length 为字的数量, sizeof = length*4
\param 读出来的 Outbuff指针
\retval none
********************************************************************/
void BSP_fmc_read_Wrod(uint32_t address, uint16_t length, uint32_t* Outbuff)
{
for(int i = 0; i < length; i++)
{
Outbuff =*(volatile uint32_t*)(address);
address = address + 4;
}
}
/********************************************************************
\brief 不检查 连续写入length个字到flash
\param length 为字的数量, sizeof = length*4
\param 要写入的 u32 buff
\retval none
********************************************************************/
void BSP_fmc_write_Word_NoCheck(uint32_t address, uint32_t length, uint32_t* data_32)
{
/* unlock the flash program erase controller */
fmc_unlock();
/* clear pending flags */
fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_OPERR | FMC_FLAG_WPERR | FMC_FLAG_PGMERR | FMC_FLAG_PGSERR);
/* write data_32 to the corresponding address */
for(int i=0; i<length; i++)
{
if(FMC_READY == fmc_word_program(address, data_32))
{
address = address + 4;
}
}
fmc_lock();
}
/********************************************************************
\brief 擦除某个扇区中的某一页(4KB)
\param Sector起始地址
\param 页 index: 0 ~ 31
\retval none
********************************************************************/
void BSP_fmc_erase_page(uint32_t sector_addr, int index)
{
fmc_unlock();
fmc_flag_clear(FMC_FLAG_END| FMC_FLAG_WPERR| FMC_FLAG_PGMERR);
fmc_page_erase(sector_addr + FMC_PAGE_SIZE*index);
fmc_lock();
}
/********************************************************************
\brief 擦除某个扇区中的多页(4KB)
\param Sector起始地址
\param start_page_index 起始页 : 0 ~ 63
\param page_num 页数量 : 1 ~ 64(256kb)
\note 跨扇区擦除,最多支持2个连续的扇区
\retval none
********************************************************************/
void BSP_fmc_erase_multi_pages(uint32_t sector_addr, int start_page_index, int page_num)
{
fmc_unlock();
fmc_flag_clear(FMC_FLAG_END| FMC_FLAG_WPERR| FMC_FLAG_PGMERR);
for(int i = start_page_index; i < (page_num + start_page_index); i++)
{
fmc_page_erase(sector_addr + FMC_PAGE_SIZE*i);
}
fmc_lock();
}
/********************************************************************
\brief 擦除整个bank
\param void
\note erase whole bank1
\retval none
********************************************************************/
void BSP_fmc_erase_bank1(void)
{
fmc_unlock();
fmc_flag_clear(FMC_FLAG_END| FMC_FLAG_WPERR| FMC_FLAG_PGMERR);
fmc_bank1_erase();
fmc_lock();
}
/*!
\brief CHECK 4KB 页内容是否为空(FF)
\paramaddress实际地址(Must 4KB 对齐)
\paramsec_count 扇区数量
\retval TRUE Blank FALSE Not Blank
*/
bool BSP_fmc_page_is_blank_Check(uint32_t address)
{
uint32_treadout = 0;
for(int i = 0; i < FMC_PAGE_SIZE; i+=4)
{
readout = *(volatile int32_t*)(address + i);
if(readout != 0xffffffff)
{
return false;
}
}
return true;
}
/*!
\brief CHECK 一个扇区内容是否为空(FF)
\paramaddress实际地址(Must 扇区 对齐)
\retval TRUE Blank FALSE Not Blank
\note: 此函数只针对128kb大小的扇区
*/
bool BSP_fmc_sectors_is_blank_Check(uint32_t address)
{
uint32_t buff;
for(int i = 0; i < SIZE_128KB; i+=4)
{
buff = *(volatile uint32_t*)(address + i);
if(buff != 0xffffffff)
{
returnfalse;
}
}
return true;
}
/*!
\brief get the sector number, size and range of the given address
\paramaddress: The flash address
\param none
\retval fmc_sector_info_struct: The information of a sector
*/
fmc_sector_info_struct fmc_sector_info_get(uint32_t addr)
{
fmc_sector_info_struct sector_info;
uint32_t temp = 0x00000000U;
if((FMC_START_ADDRESS <= addr)&&(FMC_END_ADDRESS >= addr)) {
if ((FMC_BANK1_START_ADDRESS > addr)) {
/* bank0 area */
temp = (addr - FMC_BANK0_START_ADDRESS) / SIZE_16KB;
if (4U > temp) {
sector_info.sector_name = (uint32_t)temp;
sector_info.sector_num = CTL_SN(temp);
sector_info.sector_size = SIZE_16KB;
sector_info.sector_start_addr = FMC_BANK0_START_ADDRESS + (SIZE_16KB * temp);
sector_info.sector_end_addr = sector_info.sector_start_addr + SIZE_16KB - 1;
} else if (8U > temp) {
sector_info.sector_name = 0x00000004U;
sector_info.sector_num = CTL_SN(4);
sector_info.sector_size = SIZE_64KB;
sector_info.sector_start_addr = 0x08010000U;
sector_info.sector_end_addr = 0x0801FFFFU;
} else {
temp = (addr - FMC_BANK0_START_ADDRESS) / SIZE_128KB;
sector_info.sector_name = (uint32_t)(temp + 4);
sector_info.sector_num = CTL_SN(temp + 4);
sector_info.sector_size = SIZE_128KB;
sector_info.sector_start_addr = FMC_BANK0_START_ADDRESS + (SIZE_128KB * temp);
sector_info.sector_end_addr = sector_info.sector_start_addr + SIZE_128KB - 1;
}
} else {
/* bank1 area */
temp = (addr - FMC_BANK1_START_ADDRESS) / SIZE_16KB;
if (4U > temp) {
sector_info.sector_name = (uint32_t)(temp + 12);
sector_info.sector_num = CTL_SN(temp + 16);
sector_info.sector_size = SIZE_16KB;
sector_info.sector_start_addr = FMC_BANK0_START_ADDRESS + (SIZE_16KB * temp);
sector_info.sector_end_addr = sector_info.sector_start_addr + SIZE_16KB - 1;
} else if (8U > temp) {
sector_info.sector_name = 0x00000010;
sector_info.sector_num = CTL_SN(20);
sector_info.sector_size = SIZE_64KB;
sector_info.sector_start_addr = 0x08110000U;
sector_info.sector_end_addr = 0x0811FFFFU;
} else if (64U > temp){
temp = (addr - FMC_BANK1_START_ADDRESS) / SIZE_128KB;
sector_info.sector_name = (uint32_t)(temp + 16);
sector_info.sector_num = CTL_SN(temp + 20);
sector_info.sector_size = SIZE_128KB;
sector_info.sector_start_addr = FMC_BANK1_START_ADDRESS + (SIZE_128KB * temp);
sector_info.sector_end_addr = sector_info.sector_start_addr + SIZE_128KB - 1;
} else {
temp = (addr - FMC_BANK1_START_ADDRESS) / SIZE_256KB;
sector_info.sector_name = (uint32_t)(temp + 20);
sector_info.sector_num = CTL_SN(temp + 8);
sector_info.sector_size = SIZE_256KB;
sector_info.sector_start_addr = FMC_BANK1_START_ADDRESS + (SIZE_256KB * temp);
sector_info.sector_end_addr = sector_info.sector_start_addr + SIZE_256KB - 1;
}
}
} else {
/* invalid address */
sector_info.sector_name = FMC_WRONG_SECTOR_NAME;
sector_info.sector_num = FMC_WRONG_SECTOR_NUM;
sector_info.sector_size = FMC_INVALID_SIZE;
sector_info.sector_start_addr = FMC_INVALID_ADDR;
sector_info.sector_end_addr = FMC_INVALID_ADDR;
}
return sector_info;
}
/*!
\brief get the sector number by a given sector name
\paramaddress: a given sector name
\param none
\retval uint32_t: sector number
*/
uint32_t sector_name_to_number(uint32_t sector_name)
{
if(11 >= sector_name){
return CTL_SN(sector_name);
}else if(23 >= sector_name){
return CTL_SN(sector_name + 4);
}else if(27 >= sector_name){
return CTL_SN(sector_name - 12);
}else{
while(1);
}
}
int bsw_drv_flash_erase ( uint32_t address )
{
fmc_sector_info_struct sector_info;
// printf("\r\nFMC erase operation:\n");
/* get information about the sector in which the specified address is located */
sector_info = fmc_sector_info_get(address);
if(FMC_WRONG_SECTOR_NAME == sector_info.sector_name){
// printf("\r\nWrong address!\n");
return CL_FAIL;
}else{
// printf("\r\nErase start ......\n");
/* unlock the flash program erase controller */
fmc_unlock();
/* clear pending flags */
fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_OPERR | FMC_FLAG_WPERR | FMC_FLAG_PGMERR | FMC_FLAG_PGSERR);
/* wait the erase operation complete*/
if(FMC_READY != fmc_sector_erase(sector_info.sector_num)){
return CL_FAIL;
}
/* lock the flash program erase controller */
fmc_lock();
// printf("\r\nAddress 0x%08X is located in the : SECTOR_NUMBER_%d !\n", address, sector_info.sector_name);
// printf("\r\nSector range: 0x%08X to 0x%08X\n", sector_info.sector_start_addr, sector_info.sector_end_addr);
// printf("\r\nSector size: %d KB\n", (sector_info.sector_size/1024));
// printf("\r\nErase success!\n");
// printf("\r\n");
return CL_OK;
}
}
//写数据前会自动先擦除
int bsw_drv_flash_write ( uint32_t address , uint8_t* buf , uint16_t length )
{
uint16_t writeNum;
uint32_t data = 0;
fmc_sector_info_struct start_sector_info;
fmc_sector_info_struct end_sector_info;
uint32_t sector_num,i;
// printf("\r\nFMC word programe operation:\n");
/* unlock the flash program erase controller */
fmc_unlock();
/* clear pending flags */
fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_OPERR | FMC_FLAG_WPERR | FMC_FLAG_PGMERR | FMC_FLAG_PGSERR);
/* get the information of the start and end sectors */
start_sector_info = fmc_sector_info_get(address);
end_sector_info = fmc_sector_info_get(address + length);
/* erase sector */
for(i = start_sector_info.sector_name; i <= end_sector_info.sector_name; i++){
sector_num = sector_name_to_number(i);
if(FMC_READY != fmc_sector_erase(sector_num)){
return CL_FAIL;
}
}
if ( length % 4 == 0 )
{
writeNum = length / 4;
}
else
{
writeNum = length / 4 + 1;
}
/* write data_32 to the corresponding address */
for(i=0; i<writeNum; i++){
memcpy ( &data , buf + i * 4 , 4 );
if(FMC_READY == fmc_word_program(address, data)){
address = address + 4;
}else{
return CL_FAIL;
}
}
/* lock the flash program erase controller */
fmc_lock();
// printf("\r\nWrite complete!\n");
// printf("\r\n");
return CL_OK;
}
int bsw_drv_flash_read ( uint32_t address , uint8_t* data_8 , uint16_t length )
{
uint16_t i;
if ( address < FLASH_BASE )//非法地址
{
return CL_FAIL;
}
for(i=0; i<length; i++){
data_8 = (*(volatile uint8_t *)(uint32_t)(address));
address++;
}
return CL_OK;
}
再说说RTC吧,RTC不仅需要提供简单的读写接口,还需要支持时间戳的提取,UTC时间转换等等,
头文件中要定义一个结构体,方便与time.h的C库时间做转换。
#ifndef __BSP_RTC_H__
#define __BSP_RTC_H__
#include "gd32f4xx.h"
#include <stdio.h>
#include <stdbool.h>
#include <time.h>
#define RTC_CLOCK_SOURCE_LXTAL // RTC使用外部低速时钟
/*ms 级精确时间 */
typedef struct
{
int tm_sec; /* 秒,范围从 0 到 59 */
int tm_min; /* 分,范围从 0 到 59 */
int tm_hour; /* 小时,范围从 0 到 23 */
int tm_mday; /* 月份中的第几天,范围从 1 到 31 */
int tm_mon; /* 月,范围从1到12(和系统time不同) */
int tm_year; /* 2000年起的年份(和系统time不同)*/
int tm_wday; /* 一周中的第几天,范围从 1 到 7 (和系统time不同)*/
int tm_yday; /* 一年中的第几天,范围从 0 到 365*/
int tm_subsec; /* ms */
}hw_rtc;
//RTC初始化
void BSP_RTC_Init(void);
void BSP_RTC_time_Set(uint8_t year, uint8_t month, uint8_t date,\
uint8_t hour,uint8_t minute,uint8_t second);
void BSP_RTC_time_Get( hw_rtc *p );
void BSP_RTC_str_time_Get(char *buff);
uint32_t BSP_RTC_count_Get(void);
#endif
如何调用C库里的mktime() 函数?上干货吧,直接分享源码:
#include "bsp_rtc.h"
//BCD转二进制
uint8_t RTC_BCDToByte(uint8_t Value)
{
uint8_t bit;
uint8_t retValue;
bit = (Value >> 4) & 0x0F;
bit = Value & 0x0F;
retValue = bit * 10 + bit;
return (retValue);
}
//二进制转BCD
uint8_t RTC_ByteToBCD(uint8_t Value)
{
uint8_t bit;
uint8_t retValue;
bit = Value % 10;
bit = Value % 100 / 10;
retValue = (bit << 4) | bit;
return (retValue);
}
//RTC预配置功能
void rtc_pre_config(void)
{
__IO uint32_t prescaler_a = 0, prescaler_s = 0;
#if defined (RTC_CLOCK_SOURCE_IRC32K)
rcu_osci_on(RCU_IRC32K);
rcu_osci_stab_wait(RCU_IRC32K);
rcu_rtc_clock_config(RCU_RTCSRC_IRC32K);
prescaler_s = 0x13F;
prescaler_a = 0x63;
#elif defined (RTC_CLOCK_SOURCE_LXTAL)
rcu_osci_on(RCU_LXTAL);
rcu_osci_stab_wait(RCU_LXTAL);
rcu_rtc_clock_config(RCU_RTCSRC_LXTAL);
prescaler_s = 0xFF; // ck_spre频率 = ck_apre/(prescaler_s+1) = 256/(255+1)=1HZ
prescaler_a = 0x7F; // ck_apre频率 = RTC_CLOCK/(prescaler_a+1) = 32768/(127+1)=256HZ
#else
#error RTC clock source should be defined.
#endif /* RTC_CLOCK_SOURCE_IRC32K */
rcu_periph_clock_enable(RCU_RTC);
//等待 同步机制
while(SUCCESS != rtc_register_sync_wait())
{
};
}
//RTC初始化
void BSP_RTC_Init(void)
{
/* enable access to RTC registers in Backup domain*/
rcu_periph_clock_enable(RCU_PMU);
pmu_backup_write_enable();
rtc_pre_config();
}
/*******************************************************************!
\brief使用固定格式设置时间,默认东八区
\paramyear: 0 ~ 99 (十进制) From 2000
month: 1 ~ 12 (十进制)
date: 1 ~ 31 (十进制)
day_of_week:1 ~7 (十进制)
hour: 0 ~ 23
minute: 0 ~ 59
second: 0 ~ 59
\param none
\retval none
*******************************************************************/
void BSP_RTC_time_Set(uint8_t year, uint8_t month, uint8_t date,\
uint8_t hour, uint8_t minute,uint8_t second)
{
if((year > 99) || (month > 12) || (date > 31) )
{
return;
}
if((month == 0) || (date == 0))
{
return;
}
if((hour > 59) || (minute > 59) || (second > 59))
{
return;
}
//设置RTC时间值
rtc_parameter_struct rtc_initpara;
rtc_initpara.factor_asyn = 0x7F;
rtc_initpara.factor_syn = 0xFF;
rtc_initpara.year = RTC_ByteToBCD(year);
rtc_initpara.day_of_week = RTC_SATURDAY;// 一般用不到
rtc_initpara.month = RTC_ByteToBCD(month);
rtc_initpara.date = RTC_ByteToBCD(date & 0x1F);// 防止超过31
rtc_initpara.display_format = RTC_24HOUR;
rtc_initpara.am_pm = RTC_AM;
rtc_initpara.hour = RTC_ByteToBCD(hour);
rtc_initpara.minute = RTC_ByteToBCD(minute);
rtc_initpara.second = RTC_ByteToBCD(second);
//RTC当前时间配置
if(ERROR == rtc_init(&rtc_initpara))
{
printf("\n\r** RTC time configuration failed! **\n\r");
}
else
{
printf("\n\r** RTC time configuration success! **\n\r");
}
}
/* 从硬件寄存器中获取时间*/
void BSP_RTC_time_Get( hw_rtc *p )
{
uint32_t time_subsecond = 0;
rtc_parameter_struct rtc_read;
rtc_current_time_get(&rtc_read);
time_subsecond = rtc_subsecond_get();
time_subsecond = (1000 - (time_subsecond*1000+1000)/400);
p->tm_year = RTC_BCDToByte(rtc_read.year);// form 2000
p->tm_mon = RTC_BCDToByte(rtc_read.month);
p->tm_mday = RTC_BCDToByte(rtc_read.date);
p->tm_hour = RTC_BCDToByte(rtc_read.hour);
p->tm_min = RTC_BCDToByte(rtc_read.minute);
p->tm_sec = RTC_BCDToByte(rtc_read.second);
p->tm_wday = 1; /*星期预留不使用*/
p->tm_subsec = time_subsecond;
}
/*
获取RTC硬件时间,UTC-0时区
*/
void BSP_RTC_str_time_Get(char *buff)
{
hw_rtc hw_RTC;
BSP_RTC_time_Get(&hw_RTC);
sprintf(buff, "20%02d-%02d-%02dT%02d:%02d:%02d", hw_RTC.tm_year,hw_RTC.tm_mon,\
hw_RTC.tm_mday,hw_RTC.tm_hour, hw_RTC.tm_min, hw_RTC.tm_sec);
}
/*************************************************************************
* Function :从RTC获取时间戳 (UTC-0 Zone)年月日时分秒-->时间戳
* Description:时间戳:公元1970年1月1日(00:00:00 GMT)(格林威治时间)秒
算起至今的UTC时间所经过的秒数.(timestamp没有时区之分)
UTC(Coodinated Universal Time),协调世界时,又称世界统一时间
* Input :void
* Output :None
* Return :时间戳
************************************************************************/
uint32_t BSP_RTC_count_Get(void)
{
struct tm stmT;
hw_rtc hw_RTC;
uint32_t count = 0;
BSP_RTC_time_Get(&hw_RTC);
stmT.tm_year = hw_RTC.tm_year + 100;
stmT.tm_mon = hw_RTC.tm_mon - 1;
stmT.tm_hour = hw_RTC.tm_hour;
stmT.tm_mday = hw_RTC.tm_mday;
stmT.tm_min = hw_RTC.tm_min;
stmT.tm_sec = hw_RTC.tm_sec;
stmT.tm_isdst = 0;
count = mktime( &stmT );
return count;
}
写的确实不错 trucyw 发表于 2024-6-3 08:20
写的确实不错
哈哈,一起切磋交流,这些代码都是项目级代码,后续还会更新一些,bsp其实不多,但是有了这些通用接口会方便很多 SPI驱动来了
#include "bsp_spi.h"
//3路独立SPI接口:
// 1. SPI0 --> SPI Flash
// 2. SPI2 --> W5500
// 3. SPI3 --> RN8302
// ALL SPI interfaces with a frequency of up to 30 MHz
/*
SPI0_NSS PA4
SPI0_SCK PA5
SPI0_MISO PA6
SPI0_MOSI PA7
SPI0 --> APB2 = 120M
*/
void BSP_SPI0_Init(void)
{
spi_parameter_structspi_init_struct;
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_SPI0);
/* SPI0 GPIO config AF5 */
gpio_af_set(GPIOA, GPIO_AF_5, GPIO_PIN_5 | GPIO_PIN_6 |GPIO_PIN_7);
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_5 | GPIO_PIN_6 |GPIO_PIN_7);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5 | GPIO_PIN_6 |GPIO_PIN_7);
/* set SPI0_NSS as GPIO*/
gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_4);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_4);
/* SPI0 parameter config */
spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
spi_init_struct.device_mode = SPI_MASTER;
spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT;
spi_init_struct.clock_polarity_phase = SPI_CK_PL_HIGH_PH_2EDGE;//FLASH芯片支持SPI模式0及模式3,据此设置CPOL CPHA
spi_init_struct.nss = SPI_NSS_SOFT;
spi_init_struct.prescale = SPI_PSC_8 ;// 15M
spi_init_struct.endian = SPI_ENDIAN_MSB;
spi_init(SPI0, &spi_init_struct);
spi_enable(SPI0);
}
/*
SPI1_MOSI PB15
SPI1_MISO PB14
SPI1_SCK PB13
SPI1_NSS PB12
*/
void BSP_SPI1_Init(void)
{
spi_parameter_structspi_init_struct;
rcu_periph_clock_enable(RCU_GPIOB);
rcu_periph_clock_enable(RCU_SPI1);
/* SPI1 GPIO config AF5 */
gpio_af_set(GPIOB, GPIO_AF_5, GPIO_PIN_13 | GPIO_PIN_14 |GPIO_PIN_15);
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_13 | GPIO_PIN_14 |GPIO_PIN_15);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13 | GPIO_PIN_14 |GPIO_PIN_15);
/* set SPI1_NSS as GPIO*/
gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_12);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_12);
/* SPI1 parameter config */
spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
spi_init_struct.device_mode = SPI_MASTER;
spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT;
spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
spi_init_struct.nss = SPI_NSS_SOFT;
spi_init_struct.prescale = SPI_PSC_8;
spi_init_struct.endian = SPI_ENDIAN_MSB;
spi_init(SPI1, &spi_init_struct);
spi_enable(SPI1);
}
/*For w5500
SPI2_MOSI PC12
SPI2_MISO PC11
SPI2_SCK PC10
SPI2_NSS PA15
spi2 form APB1,Fmax=60MHz
*/
void BSP_SPI2_Init(void)
{
spi_parameter_structspi_init_struct;
rcu_periph_clock_enable(RCU_GPIOC);
rcu_periph_clock_enable(RCU_SPI2);
/* SPI1 GPIO config AF6 */
gpio_af_set(GPIOC, GPIO_AF_6, GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12);
gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12);
/* set SPI2_NSS as GPIO*/
gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_15);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_15);
/* SPI1 parameter config */
spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
spi_init_struct.device_mode = SPI_MASTER;
spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT;
spi_init_struct.clock_polarity_phase = SPI_CK_PL_HIGH_PH_2EDGE; //or SPI_CK_PL_LOW_PH_1EDGE is OK, see datasheet.
spi_init_struct.nss = SPI_NSS_SOFT;
spi_init_struct.prescale = SPI_PSC_4; // 15Mbps
spi_init_struct.endian = SPI_ENDIAN_MSB;
spi_init(SPI2, &spi_init_struct);
spi_enable(SPI2);
}
/*For rn8302b
SPI3_NSS PE11
SPI3_SCK PE12
SPI3_MISO PE13
SPI3_MOSI PE14
rn8302b Max spi speed = 3.5Mbit/s from datasheet
spi3 APB2 = 120Mhz
*/
void BSP_SPI3_Init(void)
{
spi_parameter_struct spi_init_struct;
rcu_periph_clock_enable(RCU_GPIOE);
rcu_periph_clock_enable(RCU_SPI3);
/* configure SPI3 GPIO AF5*/
gpio_af_set(GPIOE, GPIO_AF_5, GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14);
gpio_mode_set(GPIOE, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14);
gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14);
/* set SPI3_NSS as GPIO*/
gpio_mode_set(GPIOE, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_11);
gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_11);
/* configure SPI3 parameter */
spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
spi_init_struct.device_mode = SPI_MASTER;
spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT;
spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_2EDGE;
spi_init_struct.nss = SPI_NSS_SOFT;
spi_init_struct.prescale = SPI_PSC_64;
spi_init_struct.endian = SPI_ENDIAN_MSB;
spi_init(SPI3, &spi_init_struct);
spi_enable(SPI3);
}
uint8_t BSP_SPIX_SendRecv(uint32_t phy_spix, uint8_t Byte)
{
//int retry = 0;
/* loop while data register in not empty */
while(RESET == spi_i2s_flag_get(phy_spix, SPI_FLAG_TBE));
/* send byte through the SPIx peripheral */
spi_i2s_data_transmit(phy_spix, Byte);
/* wait to receive a byte */
while(RESET == spi_i2s_flag_get(phy_spix, SPI_FLAG_RBNE))
{
// retry++;
// for(int i = 0; i < 0xfff; i++){};
// if(retry > 8000)
// {
// return 0;
// }
};
/* return the byte read from the SPI bus */
return(spi_i2s_data_receive(phy_spix));
} 我感觉可以把rtos那层去掉 直接把BSP库复制过来,不用的外设屏蔽掉。 GD32F470支持按页(每页4KB)擦除,这对于文件系统(如FATFS)的移植非常方便。 对于1MB容量的GD32F470VGT型号,没有定义第8、9、10、11扇区,因此软件上兼容1到3MB型号。 9dome猫 发表于 2024-6-30 23:18
GD32F470支持按页(每页4KB)擦除,这对于文件系统(如FATFS)的移植非常方便。 ...
小页对于flash模拟eeprom也方便,对
文件系统底层效率更高 这是以前瞎整的,都没时间弄了,后续有空了,再整理一下,把代码压缩包传上来~ GD芯片虽然兼容ST,但是不是100%兼容, caizhiwei 发表于 2024-7-8 11:02
这是以前瞎整的,都没时间弄了,后续有空了,再整理一下,把代码压缩包传上来~ ...
UP主,传上来下BSP部分的代码呀,多谢了,最近正好有项目需要用GD的芯片
页:
[1]