返回列表 发新帖

SAM4E-EK开发板代码解读11——EEPROM

[复制链接]

21

主题

31

帖子

1万

积分

允许发帖

积分
10129
发表于 2020-5-14 13:53:49 | 显示全部楼层 | 阅读模式
本帖最后由 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) ;

}


回复

使用道具 举报

21

主题

31

帖子

1万

积分

允许发帖

积分
10129
发表于 2020-5-14 13:57:40 | 显示全部楼层
初始化
  1. #define I2C_FAST_MODE_SPEED  400000
  2. #define TWI_CLK_DIVIDER      2
  3. #define TWI_CLK_CALC_ARGU    4
  4. #define TWI_CLK_DIV_MAX      0xFF
  5. #define TWI_CLK_DIV_MIN      7
复制代码



回复 支持 反对

使用道具 举报

21

主题

31

帖子

1万

积分

允许发帖

积分
10129
发表于 2020-5-14 14:28:01 | 显示全部楼层
  1. //使能TWI主模式
  2. [color=Red]void twi_enable_master_mode(Twi *p_twi)[/color]
  3. {
  4.         //设置主禁用位和从禁用位
  5.         p_twi->TWI_CR = TWI_CR_MSDIS;
  6.         p_twi->TWI_CR = TWI_CR_SVDIS;

  7.         //设置主使能位
  8.         p_twi->TWI_CR = TWI_CR_MSEN;
  9. }

  10. //暂时禁用TWI主控模式
  11. void twi_disable_master_mode(Twi *p_twi)
  12. {
  13.         //设置主禁用位
  14.         p_twi->TWI_CR = TWI_CR_MSDIS;
  15. }

  16. //初始化TWI模式
  17. 如果初始化成功 就返回TWI_SUCCESS,否则返回错误代码
  18. uint32_t twi_master_init(Twi *p_twi, const twi_options_t *p_opt)
  19. {
  20.         uint32_t status = TWI_SUCCESS;

  21.         //关闭TWI中断
  22.         p_twi->TWI_IDR = ~0UL;

  23.         //虚拟读状态寄存器
  24.         p_twi->TWI_SR;

  25.         //复位TWI外设
  26.         twi_reset(p_twi);

  27.         twi_enable_master_mode(p_twi);

  28.         //选择速度
  29.         if (twi_set_speed(p_twi, p_opt->speed, p_opt->master_clk) == FAIL) {
  30.                 //所需的速度设置被拒绝
  31.                 status = TWI_INVALID_ARGUMENT;
  32.         }

  33.         if (p_opt->smbus == 1) {
  34.                 p_twi->TWI_CR = TWI_CR_QUICK;
  35.         }

  36.         return status;
  37. }

  38. //设置I2C总线速度与时钟频率
  39. uint32_t twi_set_speed(Twi *p_twi, uint32_t ul_speed, uint32_t ul_mck)
  40. {
  41.         uint32_t ckdiv = 0;
  42.         uint32_t c_lh_div;

  43.         if (ul_speed > I2C_FAST_MODE_SPEED) {
  44.                 return FAIL;
  45.         }

  46.         c_lh_div = ul_mck / (ul_speed * TWI_CLK_DIVIDER) - TWI_CLK_CALC_ARGU;

  47.         //cldiv必须适合8位,cldiv必须适合3位
  48.         while ((c_lh_div > TWI_CLK_DIV_MAX) && (ckdiv < TWI_CLK_DIV_MIN)) {
  49.                 //增加时钟分压器
  50.                 ckdiv++;
  51.                 //分割cldiv值
  52.                 c_lh_div /= TWI_CLK_DIVIDER;
  53.         }

  54.         //设置时钟波形发生器寄存器
  55.         p_twi->TWI_CWGR =
  56.                         TWI_CWGR_CLDIV(c_lh_div) | TWI_CWGR_CHDIV(c_lh_div) |
  57.                         TWI_CWGR_CKDIV(ckdiv);

  58.         return PASS;
  59. }

  60. //测试芯片是否响应给指定的I2C地址
  61. 如果找到芯片 返回TWI_SUCCESS,否则返回错误代码
  62. uint32_t twi_probe(Twi *p_twi, uint8_t uc_slave_addr)
  63. {
  64.         twi_packet_t packet;
  65.         uint8_t data = 0;

  66.         //发送数据
  67.         packet.buffer = &data;
  68.         //数据长度
  69.         packet.length = 1;
  70.         //从芯片地址
  71.         packet.chip = (uint32_t) uc_slave_addr;
  72.         //芯片内部地址
  73.         packet.addr[0] = 0;
  74.         //地址长度
  75.         packet.addr_length = 0;

  76.         //执行主写访问
  77.         return (twi_master_write(p_twi, &packet));
  78. }


  79. //内部构造TWI模块地址寄存器字段
  80. TWI模块地址寄存器先发送MSB,尺寸控制哪一个字节是MSB开始
  81. static uint32_t twi_mk_addr(const uint8_t *addr, int len)
  82. {
  83.         uint32_t val;

  84.         if (len == 0)
  85.                 return 0;

  86.         val = addr[0];
  87.         if (len > 1) {
  88.                 val <<= 8;
  89.                 val |= addr[1];
  90.         }
  91.         if (len > 2) {
  92.                 val <<= 8;
  93.                 val |= addr[2];
  94.         }
  95.         return val;
  96. }

  97. //从一个TWI兼容的从设备读取多个字节
  98. 在所有数据被读取或出现错误之前,此函数不会返回
  99. 如果读取了所有字节,返回TWI_SUCCESS,否则返回错误代码
  100. uint32_t twi_master_read(Twi *p_twi, twi_packet_t *p_packet)
  101. {
  102.         uint32_t status, cnt = p_packet->length;
  103.         uint8_t *buffer = p_packet->buffer;
  104.        
  105.         //检查参数
  106.         if (cnt == 0) {
  107.                 return TWI_INVALID_ARGUMENT;
  108.         }

  109.         //设置读取模式,从地址和3个内部地址字节长度
  110.         p_twi->TWI_MMR = 0;
  111.         p_twi->TWI_MMR = TWI_MMR_MREAD | TWI_MMR_DADR(p_packet->chip) |
  112.                         ((p_packet->addr_length << TWI_MMR_IADRSZ_Pos) &
  113.                         TWI_MMR_IADRSZ_Msk);

  114.         //设置远程芯片的内部地址
  115.         p_twi->TWI_IADR = 0;
  116.         p_twi->TWI_IADR = twi_mk_addr(p_packet->addr, p_packet->addr_length);

  117.         //发送一个开始条件
  118.         p_twi->TWI_CR = TWI_CR_START;

  119.         while (cnt > 0) {
  120.                 status = p_twi->TWI_SR;
  121.                 if (status & TWI_SR_NACK) {
  122.                         return TWI_RECEIVE_NACK;
  123.                 }

  124.                 //判断是否是最后一个字节
  125.                 if (cnt == 1) {
  126.                         p_twi->TWI_CR = TWI_CR_STOP;
  127.                 }

  128.                 if (!(status & TWI_SR_RXRDY)) {
  129.                         continue;
  130.                 }
  131.                 *buffer++ = p_twi->TWI_RHR;

  132.                 cnt--;
  133.         }

  134.         while (!(p_twi->TWI_SR & TWI_SR_TXCOMP)) {
  135.         }

  136.         p_twi->TWI_SR;

  137.         return TWI_SUCCESS;
  138. }

  139. //将多个字节写入一个TWI兼容的从设备
  140. uint32_t twi_master_write(Twi *p_twi, twi_packet_t *p_packet)
  141. {
  142.         uint32_t status, cnt = p_packet->length;
  143.         uint8_t *buffer = p_packet->buffer;

  144.         //检查参数
  145.         if (cnt == 0) {
  146.                 return TWI_INVALID_ARGUMENT;
  147.         }

  148.         //设置写入模式,从地址和3个内部地址字节长度
  149.         p_twi->TWI_MMR = 0;
  150.         p_twi->TWI_MMR = TWI_MMR_DADR(p_packet->chip) |
  151.                         ((p_packet->addr_length << TWI_MMR_IADRSZ_Pos) &
  152.                         TWI_MMR_IADRSZ_Msk);

  153.         //设置远程芯片的内部地址
  154.         p_twi->TWI_IADR = 0;
  155.         p_twi->TWI_IADR = twi_mk_addr(p_packet->addr, p_packet->addr_length);

  156.         //发送所有字节
  157.         while (cnt > 0) {
  158.                 status = p_twi->TWI_SR;
  159.                 if (status & TWI_SR_NACK) {
  160.                         return TWI_RECEIVE_NACK;
  161.                 }

  162.                 if (!(status & TWI_SR_TXRDY)) {
  163.                         continue;
  164.                 }
  165.                 p_twi->TWI_THR = *buffer++;

  166.                 cnt--;
  167.         }

  168.         while (1) {
  169.                 status = p_twi->TWI_SR;
  170.                 if (status & TWI_SR_NACK) {
  171.                         return TWI_RECEIVE_NACK;
  172.                 }

  173.                 if (status & TWI_SR_TXRDY) {
  174.                         break;
  175.                 }
  176.         }

  177.         p_twi->TWI_CR = TWI_CR_STOP;

  178.         while (!(p_twi->TWI_SR & TWI_SR_TXCOMP)) {
  179.         }

  180.         return TWI_SUCCESS;
  181. }

  182. //使能TWI中断
  183. void twi_enable_interrupt(Twi *p_twi, uint32_t ul_sources)
  184. {
  185.         //启用指定的中断
  186.         p_twi->TWI_IER = ul_sources;
  187. }

  188. //关闭TWI中断
  189. void twi_disable_interrupt(Twi *p_twi, uint32_t ul_sources)
  190. {
  191.         //关闭指定的中断
  192.         p_twi->TWI_IDR = ul_sources;
  193.         //伪读
  194.         p_twi->TWI_SR;
  195. }

  196. //得到TWI中断状态
  197. uint32_t twi_get_interrupt_status(Twi *p_twi)
  198. {
  199.         return p_twi->TWI_SR;
  200. }

  201. //读TWI中断掩码
  202. uint32_t twi_get_interrupt_mask(Twi *p_twi)
  203. {
  204.         return p_twi->TWI_IMR;
  205. }

  206. //从TWI总线读取一个字节
  207. uint8_t twi_read_byte(Twi *p_twi)
  208. {
  209.         return p_twi->TWI_RHR;
  210. }

  211. //向总线上的一个TWI从服务器发送一个字节的数据
  212. void twi_write_byte(Twi *p_twi, uint8_t uc_byte)
  213. {
  214.         p_twi->TWI_THR = uc_byte;
  215. }

  216. //使能TWI从模式
  217. void twi_enable_slave_mode(Twi *p_twi)
  218. {
  219.         //设置主禁用位和从禁用位
  220.         p_twi->TWI_CR = TWI_CR_MSDIS;
  221.         p_twi->TWI_CR = TWI_CR_SVDIS;

  222.         //设置主使能位
  223.         p_twi->TWI_CR = TWI_CR_SVEN;
  224. }

  225. //关闭TWI从模式
  226. void twi_disable_slave_mode(Twi *p_twi)
  227. {
  228.         //设置从机禁用位
  229.         p_twi->TWI_CR = TWI_CR_SVDIS;
  230. }

  231. //初始化TWI从模式
  232. void twi_slave_init(Twi *p_twi, uint32_t ul_device_addr)
  233. {
  234.         //禁用TWI中断
  235.         p_twi->TWI_IDR = ~0UL;
  236.         p_twi->TWI_SR;

  237.         //复位TWI
  238.         twi_reset(p_twi);

  239.         //在从模式下设置从地址
  240.         p_twi->TWI_SMR = TWI_SMR_SADR(ul_device_addr);

  241.         //使能从模式
  242.         twi_enable_slave_mode(p_twi);
  243. }

  244. //设置TWI从地址
  245. void twi_set_slave_addr(Twi *p_twi, uint32_t ul_device_addr)
  246. {
  247.         //设置从地址
  248.         p_twi->TWI_SMR = TWI_SMR_SADR(ul_device_addr);
  249. }

  250. //从主服务器读取数据
  251. uint32_t twi_slave_read(Twi *p_twi, uint8_t *p_data)
  252. {
  253.         uint32_t status, cnt = 0;

  254.         do {
  255.                 status = p_twi->TWI_SR;
  256.                 if (status & TWI_SR_SVACC) {
  257.                         if (!(status & TWI_SR_GACC) &&
  258.                                 ((status & (TWI_SR_SVREAD | TWI_SR_RXRDY))
  259.                                  == (TWI_SR_SVREAD | TWI_SR_RXRDY))) {
  260.                                 *p_data++ = (uint8_t) p_twi->TWI_RHR;
  261.                                 cnt++;
  262.                         }
  263.                 } else if ((status & (TWI_SR_EOSACC | TWI_SR_TXCOMP))
  264.                                         == (TWI_SR_EOSACC | TWI_SR_TXCOMP)) {
  265.                         break;
  266.                 }
  267.         } while (1);

  268.         return cnt;
  269. }

  270. //将数据写入TWI总线
  271. uint32_t twi_slave_write(Twi *p_twi, uint8_t *p_data)
  272. {
  273.         uint32_t status, cnt = 0;

  274.         do {
  275.                 status = p_twi->TWI_SR;
  276.                 if (status & TWI_SR_SVACC) {
  277.                         if (!(status & (TWI_SR_GACC | TWI_SR_SVREAD)) &&
  278.                                 (status & TWI_SR_TXRDY)) {
  279.                                 p_twi->TWI_THR = *p_data++;
  280.                                 cnt++;
  281.                         }
  282.                 } else if ((status & (TWI_SR_EOSACC | TWI_SR_TXCOMP))
  283.                                         == (TWI_SR_EOSACC | TWI_SR_TXCOMP)) {
  284.                         break;
  285.                 }
  286.         } while (1);

  287.         return cnt;
  288. }

  289. //重置TWI
  290. void twi_reset(Twi *p_twi)
  291. {
  292.         //设置SWRST位重置TWI外设
  293.         p_twi->TWI_CR = TWI_CR_SWRST;
  294.         p_twi->TWI_RHR;
  295. }

  296. //获取TWI PDC基址
  297. Pdc *twi_get_pdc_base(Twi *p_twi)
  298. {
  299.         Pdc *p_pdc_base = NULL;

  300.         if (p_twi == TWI0) {
  301.                 p_pdc_base = PDC_TWI0;
  302.         }
  303. #ifdef PDC_TWI1
  304.         else if (p_twi == TWI1) {
  305.                 p_pdc_base = PDC_TWI1;
  306.         }
  307. #endif
  308. #ifdef PDC_TWI2
  309.                 else if (p_twi == TWI2) {
  310.                         p_pdc_base = PDC_TWI2;
  311.                 }
  312. #endif
  313.         else
  314.         {
  315.                 Assert(false);
  316.         }

  317.         return p_pdc_base;
  318. }

  319. #if SAM4E
  320. //启用\禁用写保护模式
  321. void twi_set_write_protection(Twi *p_twi, bool flag)
  322. {
  323.         if (flag) {
  324.                 p_twi->TWI_WPROT_MODE = TWI_WP_KEY_VALUE | TWI_WPROT_MODE_WPROT;
  325.         } else {
  326.                 p_twi->TWI_WPROT_MODE = TWI_WP_KEY_VALUE;
  327.         }
  328. }

  329. //简要读取写入保护状态
  330. void twi_read_write_protection_status(Twi *p_twi, uint32_t *p_status)
  331. {
  332.         *p_status = p_twi->TWI_WPROT_STATUS;
  333. }
  334. #endif
复制代码
回复 支持 反对

使用道具 举报

发表回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表