STM8S208MB -> 寄存器方式实现对Flash的连续读写操作(IAR)

代码

File: STM8S208MB_Flash_Op.c

/*
	@file: STM8S208MB_Flash_Op.c
    @brief: 读写Flash
    @data: 2023-04-14
    @author: ArcherQAQ
*/

#include "STM8S208MB_Flash_Op.h"
#include "stdio.h"

u8 dataBuf[] = {0xFF, 0xFF}; // 写入Flash的数据
u8 Rec_Buf[100] = {0x00}; // 接收读取的数据, 设有100个元素

/*
/*
    @brief: 读写Flash
    @data: 2023-04-14
    @author: ArcherQAQ
*/

#include "STM8S208MB_Flash_Op.h"

u8 dataBuf[] = {0xFF, 0xFF}; // 写入Flash的数据
u8 Rec_Buf[100] = {0x00}; // 接收读取的数据, 设有100个元素

/*
    @brief      参考数据手册Flash的Memory access security system部分实现写入Flash功能
    @param      Addr: Flash中需要被写入的地址
    @param      Buf:  需要写入的数据buffer
    @return     None
*/
// High density的stm8s的Flash地址范围为0x00 8000 ~ 0x02 7FFF即20个bit所以这里用u32来存放地址
void Flash_WriteNByte(u32 Addr, u8 *Buf)
{
    u8 i = 0;
    
    // 解锁Main Program area,连续往FLASH_PUKR写入两个MASS keys(查看Flash的MASS部分)
    // 该两个keys会与硬件keys值比对
    // 如果相同则解锁
    FLASH_PUKR = 0x56;
    FLASH_PUKR = 0xAE;

    // 成功解锁后IAPSR寄存器的PUL(Program memory Unlocked Flag)会置位
    // 表示Flash解锁,允许写
    while (!(FLASH_IAPSR | (1 << 1)))
    {
    };
    
    // 将Buf中的数据写入经过PointerAttr修饰的指针变量
    for (i = 0; i < sizeof(Buf); i++)
    {
        *(PointerAttr u8*)Addr = Buf[i];
        Addr++;
    }
   
    // 完成写操作后重新给Flash上锁,防止Flash的内容corrupution
    // 通过软件清空FALSH_IAPSR的PUl即可将Flash重新上锁
    FLASH_IAPSR &= ~(1 << 1);
}

/*
    @brief      参考数据手册Flash的Memory access security system部分实现读取Flash功能
    @param      Addr: Flash中需要被读取的地址
    @param      Len:  需要读的地址的长度
    @param      Rec_Buf: 接收返回字节的缓存数组
    @return     None
*/
void Flash_ReadNByte(u32 Addr, u16 Len, u8 *Rec_Buf)
{
    u8 i;
    
    for(i = 0; i < Len; i++)
    {
      Rec_Buf[i] = *(PointerAttr u8*)Addr; // 将读到相应地址的字节返回给Rec_Buf
      Addr++; // Addr地址+1
    }
}

File: STM8S208MB_Flash_Op.h

/*
	@file: STM8S208MB_Flash_Op.h
    @brief: 读写Flash
    @data: 2023-04-14
    @author: ArcherQAQ
*/
#ifndef __STM8S208MB_FLASH_OP_H__
#define __STM8S208MB_FLASH_OP_H__

#include "iostm8s208mb.h"
#include "STM8S208MB_General.h" 

/*
  @note: 坑中坑,stm8s中普通指针变量的长度只有16bit
         但是Flash中的地址能最大能到地址为0x02 7FFF的内存单元
         这就意味着使用类型为u8*的指针变量无法指向64K(2^16)以后的地址单元
          
         然后通过在官方库函数查看 void  FLASH_ProgramByte (uint32_t Address, uint8_t Data) 
         函数,发现其通过 PointerAttr 标识来解锁Flash访问空间的限制
     
        可通过 printf("%d\n", sizeof(PointerAttr u8*)); 验证,输出为3
        表示被PointerAttr修饰的u8*型指针变量长度为3个字节
*/

/*!< Used with memory Models for code higher than 64K */
#define FAR  __far
#define PointerAttr FAR

#define FLASH_ADDR 0x27FF1 // 需要操作的Flash地址

void Flash_WriteNByte(u32 Addr, u8 *Buf);
void Flash_ReadNByte(u32 Addr, u16 Len, u8 *Rec_Buf);

#endif

File: STM8S208MB_General.h

/*
 *   @file: STM8S208MB_General.h
 *   @brief: STM8S208MB项目通用头文件
 *   @date: 2023-04-11
 *   @author: ArcherQAQ
 */
#ifndef __STM8S208MB_General_H__
#define __STM8S208MB_General_H__
/*************************包含头文件*******************************/

/*************************常用数据类型定义*************************/
/*!< Signed integer types  */
typedef   signed char     int8_t;
typedef   signed short    int16_t;
typedef   signed long     int32_t;
/*!< Unsigned integer types  */
typedef unsigned char     uint8_t;
typedef unsigned short    uint16_t;
typedef unsigned long     uint32_t;

/*!< STM8 Standard Peripheral Library old types (maintained for legacy purpose) */
typedef int32_t  s32;
typedef int16_t s16;
typedef int8_t  s8;

typedef uint32_t  u32;
typedef uint16_t u16;
typedef uint8_t  u8;
/************************通用函数声明*************************/
void CLK_Init(void);    // 时钟初始化函数
void delay(u16 cnt);    // 延迟函数声明

#endif

File: mian.c

#include "iostm8s208mb.h"
#include "STM8S208MB_General.h"
#include "STM8S208MB_Flash_Op.h"

int main( void )
{
  CLK_Init(); // 设置时钟为内部16MHz高速时钟
  delay(200);// 延时系统时钟稳定
    
  extern u8 dataBuf[];
  extern u8 Rec_Buf[];
  
  Flash_WriteNByte(FLASH_ADDR, dataBuf);
  Flash_ReadNByte(FLASH_ADDR, 2, Rec_Buf);
  
  while(1)
  {   
  	u8 i;
    for(i = 0; i < 2; i++)
    {
        printf("第%d个读到的字节为:0x%.2x\r\n", i + 1, Rec_Buf[i]);
        printf("\r\n");
        printf("\r\n");
    }
    delay(100);
  }
}

功能验证

连续在0x27FF1、0x27FF2地址中写入0xFF
写操作
连续读0x27FF1、0x27FF2两个地址
读操作

需要注意的一些点捏:)

  • u8*类型的无符号指针变量,在IAR中长度为16个bit,即2个字节;然而在VSCode中测试为32个bit,即4个字节

    这说明数据类型的长度跟平台和编译器是有关联的,不能根据刻板印象来决定数据的类型,不确定数据类型的长度,则用sizeof()打印一下其具体占用多少个字节

  • 如果不用PointerAttr 来修饰u8* 类型指针变量的话,这就意味着,其指向的地址范围为:0x0000 ~ 0xFFFF,即64k的地址大小。开始写的时候没意识到这点,直接就用u8* 类型指针变量来存放了大于64k的地址。例子中读写的地址分别为0x27FF1和0x27FF2,这两个地址明显大于0xFFFF的,将其强行存进16位长度的u8*类型指针变量,显然会发生截断的情况

    如将0x27FF1放进16位长度的u8*类型指针变量,结果为0x7FF1,这显然不是我们需要访问的地址

你可能感兴趣的:(STM8S,Embedded,开发语言,stm32,单片机)