Telink SDK 825x - 基础模块-MCU地址空间访问

        本章简单介绍telink 825x flash、ram、clock、gpio相关的说明及操作。详细说明可以查看telink Developer handlebook。

1 MCU地址空间

1.1 Flash空间

8258 flash共512K,地址为0x0 - 0x7FFFF。

BLE sdk是三地址启动,分别为0x0,0x20000, 0x40000,即三个地址都可以作为起始地址。如果编译出来的firmware不超过0x20000大小,可以设置启动地址为0x0和0x20000,如果超过0x20000大小,需要设置启动地址为0和0x40000,这样ota升级的时候,会进行乒乓升级。

ota升级流程后门会详细说明。

1) flash操作说明

  • flash操作有两种方式,直接访问地址和函数访问。

直接访问,例如:

u16 x=*(volatile u16*)0x10000;  //读flash 0x10000 两个byte
u8 data[16];
memcpy(data, 0x20000,16); //读flash 0x20000 16 byte,copy到data中

flash 函数访问,例如:

unsigned char data[16];
flash_write_page(0x50000, 16, data);
flash_read_page(0x50000,16,data);
  • flash 函数操作,读写是按page操作,擦除是按sector操作。

一个page为256 bytes,一个sector为4K。 读可以跨page,写不可以跨page,擦除一次最少擦除4K区域。

例如,

unsigned char data[32];
//错误,不能跨page写, 前16 byte在0x12000page上面,后门的在0x121000 page
flash_write_page( 0x120f0, 20, data);  

读操作不受page的限制,可以任意读超过256 bytes的数据。

  • flash读写擦除操作都会关闭中断,可能会影响蓝牙时序。

  flash的函数操作,都会先关闭中断irq_disable(),操作完后,在恢复中断irq_restore。由于蓝牙收发包也是由中断控制的,因此,flash的操作会影响蓝牙收发包。

但是只要flash操作不占用太多的时间,就不会影响蓝牙时序。例如读写操作,只要不读写太大的数据,就不会影响蓝牙时序。但是擦除操作是几十ms级的,很大可能会影响蓝牙时序。因此,在连接状态下,不允许直接调用flash_erase_sector函数擦除flash,导致破坏蓝牙断开。如果必须要在连接的时候擦除flash,可以通过时序包含的方法来时序。这个方法后面会讲到。

  •  flash操作,推荐使用函数操作。
  • 如果内置flash 512K不满足需求,也可以通过spi外挂flash。

2) flash操作函数

/**
 * @brief This function serves to erase a sector.
 * @param[in]   addr the start address of the sector needs to erase.
 * @return none
 */
_attribute_ram_code_ void flash_erase_sector(unsigned long addr);
/**
 * @brief This function writes the buffer's content to a page.
 * @param[in]   addr the start address of the page
 * @param[in]   len the length(in byte) of content needs to write into the page
 * @param[in]   buf the start address of the content needs to write into
 * @return none
 */
_attribute_ram_code_ void flash_write_page(unsigned long addr, unsigned long len, unsigned char *buf);
/**
 * @brief This function reads the content from a page to the buf.
 * @param[in]   addr the start address of the page
 * @param[in]   len the length(in byte) of content needs to read out from the page
 * @param[out]  buf the start address of the buffer
 * @return none
 */
_attribute_ram_code_ void flash_read_page(unsigned long addr, unsigned long len, unsigned char *buf);

3) flash函数重新封装(跨page和spi 外部flash)

重新封装的flash函数,可以跨page写数据,并且包含了spi 外置flash的实现。

#include "hal_typedef.h"

#define IRQ_DISABLE 1
#define WAIT_UNTIL_FINISHED \
	do { \
		reg_v = reg_spi_ctrl; \
	} \
	while (reg_v & FLD_SPI_BUSY)

_attribute_ram_code_ void exflash_erase_sector(u32 addr)
{
	register u8 u8data;
	register u8 reg_v;

	#if IRQ_DISABLE
	u8 r = irq_disable();
	#endif
	
	reg_spi_ctrl = FLD_SPI_MASTER_MODE_EN;
	reg_spi_data = FLASH_WRITE_ENABLE_CMD; WAIT_UNTIL_FINISHED;
	reg_spi_ctrl = FLD_SPI_CS | FLD_SPI_MASTER_MODE_EN;
	
	reg_spi_ctrl = FLD_SPI_MASTER_MODE_EN;
	reg_spi_data = FLASH_SECT_ERASE_CMD; WAIT_UNTIL_FINISHED;
	reg_spi_data = addr >> 16; WAIT_UNTIL_FINISHED;
	reg_spi_data = addr >> 8; WAIT_UNTIL_FINISHED;
	reg_spi_data = addr; WAIT_UNTIL_FINISHED;
	reg_spi_ctrl = FLD_SPI_CS | FLD_SPI_MASTER_MODE_EN;

	reg_spi_ctrl = FLD_SPI_MASTER_MODE_EN;
   	reg_spi_data = FLASH_READ_STATUS_CMD; WAIT_UNTIL_FINISHED;
	reg_spi_ctrl = FLD_SPI_MASTER_MODE_EN | FLD_SPI_DATA_OUT_DIS | FLD_SPI_RD;
	u8data = reg_spi_data; WAIT_UNTIL_FINISHED;
	do {u8data = reg_spi_data; WAIT_UNTIL_FINISHED;} while(u8data & 0x01);
	reg_spi_ctrl = FLD_SPI_CS | FLD_SPI_MASTER_MODE_EN | FLD_SPI_DATA_OUT_DIS;

	#if IRQ_DISABLE
	irq_restore(r);
	#endif
}

_attribute_ram_code_ void exflash_erase_chip(void)
{
	register u8 u8data;
	register u8 reg_v;

	#if IRQ_DISABLE
	u8 r = irq_disable();
	#endif
	
	reg_spi_ctrl = FLD_SPI_MASTER_MODE_EN;
	reg_spi_data = FLASH_WRITE_ENABLE_CMD; WAIT_UNTIL_FINISHED;
	reg_spi_ctrl = FLD_SPI_CS | FLD_SPI_MASTER_MODE_EN;
	
	reg_spi_ctrl = FLD_SPI_MASTER_MODE_EN;
	reg_spi_data = FLASH_CHIP_ERASE_CMD; WAIT_UNTIL_FINISHED;
	reg_spi_ctrl = FLD_SPI_CS | FLD_SPI_MASTER_MODE_EN;

	reg_spi_ctrl = FLD_SPI_MASTER_MODE_EN;
   	reg_spi_data = FLASH_READ_STATUS_CMD; WAIT_UNTIL_FINISHED;
	reg_spi_ctrl = FLD_SPI_MASTER_MODE_EN | FLD_SPI_DATA_OUT_DIS | FLD_SPI_RD;
	u8data = reg_spi_data; WAIT_UNTIL_FINISHED;
	do {u8data = reg_spi_data; WAIT_UNTIL_FINISHED;} while(u8data & 0x01);
	reg_spi_ctrl = FLD_SPI_CS | FLD_SPI_MASTER_MODE_EN | FLD_SPI_DATA_OUT_DIS;

	#if IRQ_DISABLE
	irq_restore(r);
	#endif
}

_attribute_ram_code_ void exflash_write_page(u32 addr, u32 len, u8 *buf)
{
	register u8 u8data;
	register u8 reg_v;
	register u32 i = 0;

	#if IRQ_DISABLE
	u8 r = irq_disable();
	#endif

	/* CS = low, enable master mode, enable SDO, enable write */
	reg_spi_ctrl = FLD_SPI_MASTER_MODE_EN;
	reg_spi_data = FLASH_WRITE_ENABLE_CMD; WAIT_UNTIL_FINISHED;
	/* CS = high, enable master mode, enable SDO, enable write */
	reg_spi_ctrl = FLD_SPI_CS | FLD_SPI_MASTER_MODE_EN;
	
	/* CS = low, enable master mode, enable SDO, enable write */
	reg_spi_ctrl = FLD_SPI_MASTER_MODE_EN;
	reg_spi_data = FLASH_WRITE_CMD; WAIT_UNTIL_FINISHED;
	reg_spi_data = addr >> 16; WAIT_UNTIL_FINISHED;
	reg_spi_data = addr >> 8; WAIT_UNTIL_FINISHED;
	reg_spi_data = addr; WAIT_UNTIL_FINISHED;
	/* continue to send len bytes */
	do {reg_spi_data = buf[i++]; WAIT_UNTIL_FINISHED;} while(--len);
	/* CS = high, enable master mode, enable SDO, enable write */
	reg_spi_ctrl = FLD_SPI_CS | FLD_SPI_MASTER_MODE_EN;

	/* CS = low, enable master mode, enable SDO, enable write */
	reg_spi_ctrl = FLD_SPI_MASTER_MODE_EN;
   	reg_spi_data = FLASH_READ_STATUS_CMD; WAIT_UNTIL_FINISHED;
	/* CS is still low, enable master mode, disable SDO, enable read */
	reg_spi_ctrl = FLD_SPI_MASTER_MODE_EN | FLD_SPI_DATA_OUT_DIS | FLD_SPI_RD;
	/* dummy read in order to output 8 spi clock */
	u8data = reg_spi_data; WAIT_UNTIL_FINISHED;
	/* keep reading until bit 0 of STATUS register changed to 0 */
	do {u8data = reg_spi_data; WAIT_UNTIL_FINISHED;} while(u8data & 0x01);
	/* CS changed to high, enable master mode, disable SDO, enable read */
	reg_spi_ctrl = FLD_SPI_CS | FLD_SPI_MASTER_MODE_EN | FLD_SPI_DATA_OUT_DIS;
	
	#if IRQ_DISABLE
	irq_restore(r);
	#endif
}


_attribute_ram_code_ void exflash_read_page(u32 addr, u32 len, u8 *buf)
{
	register u8 u8data;
	register u8 reg_v;
	register u32 i;

	#if IRQ_DISABLE
	u8 r = irq_disable();
	#endif

	// CS = low, enable master mode, enable SDO, enable write
	reg_spi_ctrl = FLD_SPI_MASTER_MODE_EN;
	reg_spi_data = FLASH_READ_CMD; WAIT_UNTIL_FINISHED;
	reg_spi_data = addr >> 16; WAIT_UNTIL_FINISHED;
	reg_spi_data = addr >> 8; WAIT_UNTIL_FINISHED;
	reg_spi_data = addr >> 0; WAIT_UNTIL_FINISHED;

	// CS = low, enable master mode, disable SDO, enable read
	reg_spi_ctrl = FLD_SPI_MASTER_MODE_EN | FLD_SPI_DATA_OUT_DIS | FLD_SPI_RD;
	// dummy read in order to output 8 spi clock
    u8data = reg_spi_data; WAIT_UNTIL_FINISHED;
	// continue to send len*8 spi clock and save len-1 bytes
    for (i = 0; i < len - 1; i++) {
        buf[i] = reg_spi_data; WAIT_UNTIL_FINISHED;
    }
	// save the last byte
	buf[i] = reg_spi_data;
	// CS = high, enable master mode, disable SDO, enable write
	reg_spi_ctrl = FLD_SPI_CS | FLD_SPI_MASTER_MODE_EN | FLD_SPI_DATA_OUT_DIS;

	#if IRQ_DISABLE
	irq_restore(r);
	#endif
}

void exflash_read_id( u8 *manufacturer_id, u16 *device_id)
{
	u8 buf[3];
	u8 reg_v;
	int i;
	
	#if IRQ_DISABLE
	unsigned char r = irq_disable();
	#endif
	
	reg_spi_ctrl = FLD_SPI_MASTER_MODE_EN;
	reg_spi_data = FLASH_GET_JEDEC_ID; WAIT_UNTIL_FINISHED;
	reg_spi_ctrl = FLD_SPI_MASTER_MODE_EN | FLD_SPI_DATA_OUT_DIS | FLD_SPI_RD;
    buf[0] = reg_spi_data; WAIT_UNTIL_FINISHED;
    for (i = 0; i < 2; i++) {
        buf[i] = reg_spi_data; WAIT_UNTIL_FINISHED;
    }
	buf[i] = reg_spi_data;
	reg_spi_ctrl = FLD_SPI_CS | FLD_SPI_MASTER_MODE_EN | FLD_SPI_DATA_OUT_DIS;
	*manufacturer_id = buf[0];
	*device_id = (buf[1]<<8)|buf[2];

	#if IRQ_DISABLE
	irq_restore(r);
	#endif
}

typedef void (*FLASH_WRITE_PAGE)(u32 addr, u32 len, u8 *buf);
typedef void (*FLASH_READ_PAGE)(u32 addr, u32 len, u8 *buf);
typedef void (*FLASH_ERASE_SECTOR)(u32 addr);
typedef void (*FLASH_ERASE_CHIP)(void);

_attribute_ram_code_ void hal_flash_write_page( u32 addr, u32 len, u8 *buf)
{
	FLASH_WRITE_PAGE flash_write_page_fn;
	u8 left = 0;

	if( addr < 0x80000 ){
		flash_write_page_fn = flash_write_page;
	}
	else{
		flash_write_page_fn = exflash_write_page;
		addr -= 0x80000;
	}
	
	left = addr%256;
	if (left){
		left = 256 - left;
		if (left >= len){
			flash_write_page_fn( addr, len, buf );
			return;
		}
		else {
			flash_write_page_fn( addr, left, buf );
			addr += left;
			buf += left;
			len -= left;
		}
	}
	while (len>=256){
		flash_write_page_fn( addr, 256, buf );
		addr += 256;
		buf += 256;
		len -= 256;
	}
	if (len > 0){
		flash_write_page_fn( addr, len, buf );
	}			
}

void hal_flash_erase_sector( u32 addr)
{
	FLASH_ERASE_SECTOR flash_erase_sector_fn;
	if( addr < 0x80000 )
		flash_erase_sector_fn = flash_erase_sector;
	else {
		flash_erase_sector_fn = exflash_erase_sector;
		addr -= 0x80000;
	}
	flash_erase_sector_fn(addr);
}

_attribute_ram_code_ void hal_flash_read_page( u32 addr, u32 len, u8 *buf)
{
	FLASH_READ_PAGE  flash_read_page_fn;
	if( addr < 0x80000 ){
		flash_read_page_fn = flash_read_page;
	}
	else{
		flash_read_page_fn = exflash_read_page;
		addr -= 0x80000;
	}
	flash_read_page_fn( addr, len, buf );
}

void hal_flash_read_id( u8 *manufacturer_id, u16 *device_id)
{
	exflash_read_id(manufacturer_id, device_id);
}

void hal_flash_extern_eraseall(void)
{
	exflash_erase_chip();
}

void hal_flash_extern_enable(u8 enable)
{
	if(0x0 == enable)
	{
		//disable
	}
	else
	{
		//enable
		//spi_master_init((unsigned char)(CLOCK_SYS_CLOCK_HZ/(2*500000)-1),SPI_MODE0);          //div_clock. spi_clk = sys_clk/((div_clk+1)*2),mode select
		spi_master_init((unsigned char)0,SPI_MODE0);          //div_clock. spi_clk = sys_clk/((div_clk+1)*2),mode select
		spi_master_gpio_set(SPI_GPIO_GROUP_A2A3A4D6);    //master mode ��spi pin set
	}
}


1.2 SRAM操作

SRAM 有32K、48K、64K ,地址空间分别为:

32K:0x840000 - 0x848000

48K: 0x840000 - 0x84C000

64K: 0x840000 - 0x850000

RAM又分为两部分,一部分是普通的ram空间,另一部分是retention ram(睡眠不丢数据)。

RAM空间操作也有两种方法:直接方法,函数访问。

直接访问:

u32 y=*(volatile u32*)0x840000;  //读ram 0x40000-0x40003地址的值
*(volatile u32*)0x840000 = 0x12345678; //写ram

函数访问:

//addr为实际地址-0x80000
write_reg8(addr,value);
write_reg16(addr,value);
write_reg32(addr,value);
read_reg8(addr);
read_reg16(addr);
read_reg32(addr);

注意:读写ram,要确保地址是2 byte/ 4byte字节对齐,否则会发生读写错误。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值