Mcuzone 野芯科技
标题: SAM4E-EK开发板代码解读11——EEPROM [打印本页]
作者: Mcuzone_TKN 时间: 2020-5-14 13:53
标题: SAM4E-EK开发板代码解读11——EEPROM
本帖最后由 Mcuzone_TKN 于 2020-5-14 14:29 编辑
关键词:Microchip Atmel SAM4E SAM4E-EK SAM4E16E 芯片 PCF8563 EEPROM
概述:简要解读EEPROM
EEPROM(带电可擦除编程只读存储器)是用户可更改的只读存储器(ROM),其可通过高于普通电压的作用来擦除和重新编程(重写)。
EEPROM以Byte为最小修改单位,不必将资料全部洗掉才能写入。
打开产品光盘SAM4E16E-EK/SAM4E16E-EK中文资料/softpack软件包/Atmel Studio 7,打开13a_TWI_MASTER_EXAMPLE_eeprom例子。
int main(void)
{
uint32_t i;
twi_options_t opt;
twi_packet_t packet_tx, packet_rx;
//初始化SAM系统
sysclk_init();
board_init();
//初始化控制台uart
configure_console();
//输出示例信息
puts(STRING_HEADER);
//配置systick为1ms
puts("Configure system tick to get 1ms tick period.\r");
if (SysTick_Config(sysclk_get_cpu_hz() / 1000)) {
puts("-F- Systick configuration error\r");
while (1);
}
//使能TWI外部时钟
pmc_enable_periph_clk(BOARD_ID_TWI_EEPROM);
//配置TWI驱动程序的选项
opt.master_clk = sysclk_get_cpu_hz();
opt.speed = TWI_CLK;
//配置要传送的数据包
packet_tx.chip = AT24C_ADDRESS;
packet_tx.addr[0] = EEPROM_MEM_ADDR >> 8;
packet_tx.addr[1] = EEPROM_MEM_ADDR;
packet_tx.addr_length = EEPROM_MEM_ADDR_LENGTH;
packet_tx.buffer = (uint8_t *) test_data_tx;
packet_tx.length = TEST_DATA_LENGTH;
//配置要接收的数据包
packet_rx.chip = packet_tx.chip;
packet_rx.addr[0] = packet_tx.addr[0];
packet_rx.addr[1] = packet_tx.addr[1];
packet_rx.addr_length = packet_tx.addr_length;
packet_rx.buffer = gs_uc_test_data_rx;
packet_rx.length = packet_tx.length;
if (twi_master_init(BOARD_BASE_TWI_EEPROM, &opt) != TWI_SUCCESS) {
puts("-E-\tTWI master initialization failed.\r");
while (1) ;
}
//发送测试模式到EEPROM
if (twi_master_write(BOARD_BASE_TWI_EEPROM, &packet_tx) != TWI_SUCCESS) {
puts("-E-\tTWI master write packet failed.\r");
while (1) ;
}
printf("Write:\tOK!\n\r");
//等待至少10ms
mdelay(WAIT_TIME);
//从EEPROM获得内存
if (twi_master_read(BOARD_BASE_TWI_EEPROM, &packet_rx) != TWI_SUCCESS) {
puts("-E-\tTWI master read packet failed.\r");
while (1) ;
}
puts("Read:\tOK!\r");
//比较发送和接收
for (i = 0; i < TEST_DATA_LENGTH; i++) {
if (test_data_tx != gs_uc_test_data_rx) {
puts("Data comparison:\tUnmatched!\r");
while (1) ;
}
}
puts("Data comparison:\tMatched!\r");
while (1) ;
}
作者: Mcuzone_TKN 时间: 2020-5-14 13:57
初始化
- #define I2C_FAST_MODE_SPEED 400000
- #define TWI_CLK_DIVIDER 2
- #define TWI_CLK_CALC_ARGU 4
- #define TWI_CLK_DIV_MAX 0xFF
- #define TWI_CLK_DIV_MIN 7
复制代码
作者: Mcuzone_TKN 时间: 2020-5-14 14:28
- //使能TWI主模式
- [color=Red]void twi_enable_master_mode(Twi *p_twi)[/color]
- {
- //设置主禁用位和从禁用位
- p_twi->TWI_CR = TWI_CR_MSDIS;
- p_twi->TWI_CR = TWI_CR_SVDIS;
- //设置主使能位
- p_twi->TWI_CR = TWI_CR_MSEN;
- }
- //暂时禁用TWI主控模式
- void twi_disable_master_mode(Twi *p_twi)
- {
- //设置主禁用位
- p_twi->TWI_CR = TWI_CR_MSDIS;
- }
- //初始化TWI模式
- 如果初始化成功 就返回TWI_SUCCESS,否则返回错误代码
- uint32_t twi_master_init(Twi *p_twi, const twi_options_t *p_opt)
- {
- uint32_t status = TWI_SUCCESS;
- //关闭TWI中断
- p_twi->TWI_IDR = ~0UL;
- //虚拟读状态寄存器
- p_twi->TWI_SR;
- //复位TWI外设
- twi_reset(p_twi);
- twi_enable_master_mode(p_twi);
- //选择速度
- if (twi_set_speed(p_twi, p_opt->speed, p_opt->master_clk) == FAIL) {
- //所需的速度设置被拒绝
- status = TWI_INVALID_ARGUMENT;
- }
- if (p_opt->smbus == 1) {
- p_twi->TWI_CR = TWI_CR_QUICK;
- }
- return status;
- }
- //设置I2C总线速度与时钟频率
- uint32_t twi_set_speed(Twi *p_twi, uint32_t ul_speed, uint32_t ul_mck)
- {
- uint32_t ckdiv = 0;
- uint32_t c_lh_div;
- if (ul_speed > I2C_FAST_MODE_SPEED) {
- return FAIL;
- }
- c_lh_div = ul_mck / (ul_speed * TWI_CLK_DIVIDER) - TWI_CLK_CALC_ARGU;
- //cldiv必须适合8位,cldiv必须适合3位
- while ((c_lh_div > TWI_CLK_DIV_MAX) && (ckdiv < TWI_CLK_DIV_MIN)) {
- //增加时钟分压器
- ckdiv++;
- //分割cldiv值
- c_lh_div /= TWI_CLK_DIVIDER;
- }
- //设置时钟波形发生器寄存器
- p_twi->TWI_CWGR =
- TWI_CWGR_CLDIV(c_lh_div) | TWI_CWGR_CHDIV(c_lh_div) |
- TWI_CWGR_CKDIV(ckdiv);
- return PASS;
- }
- //测试芯片是否响应给指定的I2C地址
- 如果找到芯片 返回TWI_SUCCESS,否则返回错误代码
- uint32_t twi_probe(Twi *p_twi, uint8_t uc_slave_addr)
- {
- twi_packet_t packet;
- uint8_t data = 0;
- //发送数据
- packet.buffer = &data;
- //数据长度
- packet.length = 1;
- //从芯片地址
- packet.chip = (uint32_t) uc_slave_addr;
- //芯片内部地址
- packet.addr[0] = 0;
- //地址长度
- packet.addr_length = 0;
- //执行主写访问
- return (twi_master_write(p_twi, &packet));
- }
- //内部构造TWI模块地址寄存器字段
- TWI模块地址寄存器先发送MSB,尺寸控制哪一个字节是MSB开始
- static uint32_t twi_mk_addr(const uint8_t *addr, int len)
- {
- uint32_t val;
- if (len == 0)
- return 0;
- val = addr[0];
- if (len > 1) {
- val <<= 8;
- val |= addr[1];
- }
- if (len > 2) {
- val <<= 8;
- val |= addr[2];
- }
- return val;
- }
- //从一个TWI兼容的从设备读取多个字节
- 在所有数据被读取或出现错误之前,此函数不会返回
- 如果读取了所有字节,返回TWI_SUCCESS,否则返回错误代码
- uint32_t twi_master_read(Twi *p_twi, twi_packet_t *p_packet)
- {
- uint32_t status, cnt = p_packet->length;
- uint8_t *buffer = p_packet->buffer;
-
- //检查参数
- if (cnt == 0) {
- return TWI_INVALID_ARGUMENT;
- }
- //设置读取模式,从地址和3个内部地址字节长度
- p_twi->TWI_MMR = 0;
- p_twi->TWI_MMR = TWI_MMR_MREAD | TWI_MMR_DADR(p_packet->chip) |
- ((p_packet->addr_length << TWI_MMR_IADRSZ_Pos) &
- TWI_MMR_IADRSZ_Msk);
- //设置远程芯片的内部地址
- p_twi->TWI_IADR = 0;
- p_twi->TWI_IADR = twi_mk_addr(p_packet->addr, p_packet->addr_length);
- //发送一个开始条件
- p_twi->TWI_CR = TWI_CR_START;
- while (cnt > 0) {
- status = p_twi->TWI_SR;
- if (status & TWI_SR_NACK) {
- return TWI_RECEIVE_NACK;
- }
- //判断是否是最后一个字节
- if (cnt == 1) {
- p_twi->TWI_CR = TWI_CR_STOP;
- }
- if (!(status & TWI_SR_RXRDY)) {
- continue;
- }
- *buffer++ = p_twi->TWI_RHR;
- cnt--;
- }
- while (!(p_twi->TWI_SR & TWI_SR_TXCOMP)) {
- }
- p_twi->TWI_SR;
- return TWI_SUCCESS;
- }
- //将多个字节写入一个TWI兼容的从设备
- uint32_t twi_master_write(Twi *p_twi, twi_packet_t *p_packet)
- {
- uint32_t status, cnt = p_packet->length;
- uint8_t *buffer = p_packet->buffer;
- //检查参数
- if (cnt == 0) {
- return TWI_INVALID_ARGUMENT;
- }
- //设置写入模式,从地址和3个内部地址字节长度
- p_twi->TWI_MMR = 0;
- p_twi->TWI_MMR = TWI_MMR_DADR(p_packet->chip) |
- ((p_packet->addr_length << TWI_MMR_IADRSZ_Pos) &
- TWI_MMR_IADRSZ_Msk);
- //设置远程芯片的内部地址
- p_twi->TWI_IADR = 0;
- p_twi->TWI_IADR = twi_mk_addr(p_packet->addr, p_packet->addr_length);
- //发送所有字节
- while (cnt > 0) {
- status = p_twi->TWI_SR;
- if (status & TWI_SR_NACK) {
- return TWI_RECEIVE_NACK;
- }
- if (!(status & TWI_SR_TXRDY)) {
- continue;
- }
- p_twi->TWI_THR = *buffer++;
- cnt--;
- }
- while (1) {
- status = p_twi->TWI_SR;
- if (status & TWI_SR_NACK) {
- return TWI_RECEIVE_NACK;
- }
- if (status & TWI_SR_TXRDY) {
- break;
- }
- }
- p_twi->TWI_CR = TWI_CR_STOP;
- while (!(p_twi->TWI_SR & TWI_SR_TXCOMP)) {
- }
- return TWI_SUCCESS;
- }
- //使能TWI中断
- void twi_enable_interrupt(Twi *p_twi, uint32_t ul_sources)
- {
- //启用指定的中断
- p_twi->TWI_IER = ul_sources;
- }
- //关闭TWI中断
- void twi_disable_interrupt(Twi *p_twi, uint32_t ul_sources)
- {
- //关闭指定的中断
- p_twi->TWI_IDR = ul_sources;
- //伪读
- p_twi->TWI_SR;
- }
- //得到TWI中断状态
- uint32_t twi_get_interrupt_status(Twi *p_twi)
- {
- return p_twi->TWI_SR;
- }
- //读TWI中断掩码
- uint32_t twi_get_interrupt_mask(Twi *p_twi)
- {
- return p_twi->TWI_IMR;
- }
- //从TWI总线读取一个字节
- uint8_t twi_read_byte(Twi *p_twi)
- {
- return p_twi->TWI_RHR;
- }
- //向总线上的一个TWI从服务器发送一个字节的数据
- void twi_write_byte(Twi *p_twi, uint8_t uc_byte)
- {
- p_twi->TWI_THR = uc_byte;
- }
- //使能TWI从模式
- void twi_enable_slave_mode(Twi *p_twi)
- {
- //设置主禁用位和从禁用位
- p_twi->TWI_CR = TWI_CR_MSDIS;
- p_twi->TWI_CR = TWI_CR_SVDIS;
- //设置主使能位
- p_twi->TWI_CR = TWI_CR_SVEN;
- }
- //关闭TWI从模式
- void twi_disable_slave_mode(Twi *p_twi)
- {
- //设置从机禁用位
- p_twi->TWI_CR = TWI_CR_SVDIS;
- }
- //初始化TWI从模式
- void twi_slave_init(Twi *p_twi, uint32_t ul_device_addr)
- {
- //禁用TWI中断
- p_twi->TWI_IDR = ~0UL;
- p_twi->TWI_SR;
- //复位TWI
- twi_reset(p_twi);
- //在从模式下设置从地址
- p_twi->TWI_SMR = TWI_SMR_SADR(ul_device_addr);
- //使能从模式
- twi_enable_slave_mode(p_twi);
- }
- //设置TWI从地址
- void twi_set_slave_addr(Twi *p_twi, uint32_t ul_device_addr)
- {
- //设置从地址
- p_twi->TWI_SMR = TWI_SMR_SADR(ul_device_addr);
- }
- //从主服务器读取数据
- uint32_t twi_slave_read(Twi *p_twi, uint8_t *p_data)
- {
- uint32_t status, cnt = 0;
- do {
- status = p_twi->TWI_SR;
- if (status & TWI_SR_SVACC) {
- if (!(status & TWI_SR_GACC) &&
- ((status & (TWI_SR_SVREAD | TWI_SR_RXRDY))
- == (TWI_SR_SVREAD | TWI_SR_RXRDY))) {
- *p_data++ = (uint8_t) p_twi->TWI_RHR;
- cnt++;
- }
- } else if ((status & (TWI_SR_EOSACC | TWI_SR_TXCOMP))
- == (TWI_SR_EOSACC | TWI_SR_TXCOMP)) {
- break;
- }
- } while (1);
- return cnt;
- }
- //将数据写入TWI总线
- uint32_t twi_slave_write(Twi *p_twi, uint8_t *p_data)
- {
- uint32_t status, cnt = 0;
- do {
- status = p_twi->TWI_SR;
- if (status & TWI_SR_SVACC) {
- if (!(status & (TWI_SR_GACC | TWI_SR_SVREAD)) &&
- (status & TWI_SR_TXRDY)) {
- p_twi->TWI_THR = *p_data++;
- cnt++;
- }
- } else if ((status & (TWI_SR_EOSACC | TWI_SR_TXCOMP))
- == (TWI_SR_EOSACC | TWI_SR_TXCOMP)) {
- break;
- }
- } while (1);
- return cnt;
- }
- //重置TWI
- void twi_reset(Twi *p_twi)
- {
- //设置SWRST位重置TWI外设
- p_twi->TWI_CR = TWI_CR_SWRST;
- p_twi->TWI_RHR;
- }
- //获取TWI PDC基址
- Pdc *twi_get_pdc_base(Twi *p_twi)
- {
- Pdc *p_pdc_base = NULL;
- if (p_twi == TWI0) {
- p_pdc_base = PDC_TWI0;
- }
- #ifdef PDC_TWI1
- else if (p_twi == TWI1) {
- p_pdc_base = PDC_TWI1;
- }
- #endif
- #ifdef PDC_TWI2
- else if (p_twi == TWI2) {
- p_pdc_base = PDC_TWI2;
- }
- #endif
- else
- {
- Assert(false);
- }
- return p_pdc_base;
- }
- #if SAM4E
- //启用\禁用写保护模式
- void twi_set_write_protection(Twi *p_twi, bool flag)
- {
- if (flag) {
- p_twi->TWI_WPROT_MODE = TWI_WP_KEY_VALUE | TWI_WPROT_MODE_WPROT;
- } else {
- p_twi->TWI_WPROT_MODE = TWI_WP_KEY_VALUE;
- }
- }
- //简要读取写入保护状态
- void twi_read_write_protection_status(Twi *p_twi, uint32_t *p_status)
- {
- *p_status = p_twi->TWI_WPROT_STATUS;
- }
- #endif
复制代码
欢迎光临 Mcuzone 野芯科技 (http://testbbs.mcuzone.com/) |
Powered by Discuz! X3.1 |