历史上的今天
返回首页

历史上的今天

今天是:2024年10月20日(星期日)

正在发生

2021年10月20日 | mini2440裸机编程-----IIC—读写AT24C08

2021-10-20 来源:eefocus

开始弄2440的裸机编程,争取尽快从最底层把这些硬件都熟悉掌握。


最初始从配置裸机开发环境开始的,本来想用jlink+ADS来进行下载,结果用ADS的调试器AXD通过jlink进行下载的时候,软件总是出现各种问题,这个问题折腾了有10天的时间,浪费了很长时间,最后重装了系统,都没有搞定。最后决定还是通过ADS来编译,然后用supervivi来进行下载了。现在经常出现的问题是 usb下载器总是识别不到,而且有时会导致电脑重启,应该是友善之臂提供的usb的驱动的问题,这些问题经常导致我折腾很长时间,心情很沮丧。有碰到并解决了类似问题的同学可以给我留个言。闲话少叙。


最开始写了uart的驱动试验,然后做了iic和iis的试验。先记录iic的试验,以后再补上uart的部分。


IIC(Inter-Integrated Circuit,I2C)总线是一种由PHILIPS公司开发的两线式串行总线,用于连接微处理器及其外围设备,它只需要数据线SDA和时钟线SCL,就能够实现CPU与被控IC之间、IC与IC之间进行双向传送。


s3c2440内部有一个IIC总线接口,因此为我们连接带有IIC通信模块的外围设备提供了便利。它具有四种操作模式:主设备发送模式、主设备接收模式、从设备发送模式和从设备接收模式。在这里我们只把s3c2440当做IIC总线的主设备来使用,因此只介绍前两种操作模式。


在主设备发送模式下,它的工作流程为:


1. 配置IIC模式,然后把从设备地址写入接收发送数据移位寄存器IICDS中,再把0xF0写入控制状态寄存器IICSTAT中,这时等待从设备发送应答信号,如果想要继续发送数据,那么在接收到应答信号后,再把待发送的数据写入寄存器IICDS中,清除中断标志后,再次等待应答信号;如果不想再发送数据了,那么把0x90写入寄存器IICSTAT中,清除中断标志并等待停止条件后,即完成了一次主设备的发送。


在主设备接收模式下,它的工作流程为:


1. 配置IIC模式,然后把从设备地址写入接收发送数据移位寄存器IICDS中,再把0xB0写入控制状态寄存器IICSTAT中,这时等待从设备发送应答信号,如果想要接收数据,那么在应答信号后,读取寄存器IICDS,清除中断标志;如果不想接收数据了,那么就向寄存器IICSTAT写入0x90,清除中断标志并等待停止条件后,即完成了一次主设备的接收。


数据手册中有两个流程图,非常清晰。在完成上述两个模式时,主要用到了控制寄存器IICCON、控制状态寄存器IICSTAT和发送接收数据移位寄存器IICDS。由于我们只把s3c2440当做主设备来用,并且系统的IIC总线上只有这么一个主设备,因此用来设置从设备地址的地址寄存器IICADD,和用于仲裁总线的多主设备线路控制寄存器IICLC都无需配置。寄存器IICCON的第6位和低4位用于设置IIC的时钟频率,因为IIC的时钟线SCL都是由主设备提供的。s3c2440的IIC时钟源为PCLK,当系统的PCLK为50MHz,而从设备最高需要100kHz时,可以将IICCON的第6位置1,IICCON的低4位全为0即可。寄存器IICCON的第7位用于设置是否发出应答信号,第5位用于是否使能发送和接收中断,第4位用于中断的标志,当接收或发送数据后一定要对该位进行清零,以清除中断标志。寄存器IICSTAT的高2位用于设置是哪种操作模式,当向第5位写0或写1时,则表示结束IIC或开始IIC通讯,第4位用于是否使能接收/发送数据。


由于通讯是双方的事情,在了解了主设备的操作模式后,还要清楚从设备的运行机制,两者要达到完美地结合,才能实现彼此的通讯。在这里,从设备是EEPROM——AT24C08。在看到的赵老师的博客中,他是对AT24c02a进行的读写。我觉得这两个eeprom基本上是一样的。


要想让s3c2440能够正确地对AT24C02A读写,就必须让s3c2440的时序完全按照AT24C02A的时序。AT24C02A的写操作有两种模式:字节写和页写。字节写是先接收带有写命令的设备地址信息,如果符合就应答,再接收设备内存地址信息,发出应答后,再接收要写入的数据,这样就完成了字节写过程。页写与字节写的区别就是,页写可以一次写多个数据,而字节写只能一次写一个数据。但由于AT24C02A的一页才8个字节,所以页写也最多写8个数据,而且只能在该页内写,不会发生一次页写同时写两页的情况。AT24C02A的读操作有三种模式:当前地址读、随机读和序列读。当前地址读是只能读取当前地址内的数据,它的时序是先接收带有读命令的设备地址信息,如果符合就应答,然后发送当前地址内的数据,在没有接收从主设备发来的应答信号的情况下终止该次操作。随机读的时序是,连续接收带有写命令的设备地址信息和设备内存地址信息,然后主设备重新开启IIC通信,AT24C02A再次接收到带有读命令的设备地址信息,在发出应答信号以后,发送该内存地址的数据,在没有接收到任何应答信号的情况下结束该次通信。当前地址读和随机读一次都只能读取一个数据,而序列读一次可以读取若干个数据,它的时序就是在当前地址读或随机读发出数据后,接收到了应答信号,那么AT24C02A会把下一个内存地址中的数据送出,除非AT24C02A接收不到任何应答信号,否则它会一直把下一个内存地址中的数据送出。序列读没有一页8个字节的限制。


这里是赵老师写的注意事项:


⑴清IIC中断标志语句rIICCON &= ~0x10;一定要在读写寄存器IICDS的后面,不能放到它的前面;


⑵在等待应答的死循环while内,一定要加上延时的程序;


⑶在读取AT24C02A数据时,当读到最后一个数据时,一定不能让s3c2440发送应答信号,否则以后会无法再读取AT24C02A数据,除非关电重启;


⑷在真正对AT24C02A进行读取数据时,在发送带有读命令的从设备地址后,AT24C02A会再返回一个从设备地址信息或从设备内存地址信息作为应答,所以一定要把该字节读取后抛弃,因为它不是我们所要读取的信息;(这里在看at24c08的数据手册中,并没有看到有这个。)


⑸按照AT24C02A的时序,在发送从设备地址字节时,它的最低位是0表示写,1表示读。但对于s3c2440来说,不用人为设置这一位,即是0是1都无所谓,因为这一位是由s3c2440根据是主设备发送模式还是主设备接收模式来自动设置。


我把赵老师的源程序,修改了一下,经过反复试验,刚开始弄错了i2c地址,结果只实现了eeprom的写入,读数据时,读出来的都是0xff。


赵老师的程序中,读取数据的函数如下


void rd24c02a(unsigned char wordAddr,unsigned char *buffer,int sizeofdate )

{

       int i;

       unsigned char temp;

       flag =1;

       rIICDS = devAddr;                     //

       rIICCON &= ~0x10;            //清中断标志

       rIICSTAT = 0xf0;                 //主设备发送模式

       while(flag)

              delay(100);

      

       flag = 1;

       rIICDS = wordAddr;

       rIICCON &= ~0x10;

       while(flag)

              delay(100);

             

       flag = 1;

       rIICDS =  devAddr;            //

       rIICCON &= ~0x10;           

       rIICSTAT = 0xb0;                //主设备接收模式

       while (flag)

              delay(100);

             

       flag = 1;

       temp = rIICDS;                //读取从设备地址, 这小段程序按照24c08的手册,我觉得是完全没必要的。

       rIICCON &= ~0x10;

       while(flag)

              delay(100);

 

//连续读

       for(i=0;i       {

              flag = 1;

              if(i==sizeofdate-1)                             //如果是最后一个数据

                     rIICCON &= ~0x80;                   //不再响应

              *(buffer+i) = rIICDS;

              rIICCON &= ~0x10;

              while(flag)

                     delay(100);

       }

      

       rIICSTAT = 0x90;         //结束该次通讯

       rIICCON = 0xe0;          //

      

       delay(100);                         

}


后来我修改了i2c地址之后,程序可以实现正确的读写。令我不解的是,为什么当i2c地址是错误时,mcu仍然可以收到ack信号,并且进入中断函数呢?下面附上我的源程序。

#include

#include

 

#include "def.h"

#include "option.h"

#include "2440addr.h"     

#include "2440lib.h"

#include "2440slib.h"    

#include "mmu.h"  

#include "led.h"

 

unsigned char flag;                  //应答标志

unsigned char comm;                  //命令

//unsigned char devAddr=0x10 << 1;          //从设备AT24C02A的地址

unsigned char devAddr=0xa0 << 1; //从设备AT24C02A的地址 

//IIC通信中断

void __irq IicISR(void)

{

  //   rSRCPND |= 0x1<<27;

  //   rINTPND |= 0x1<<27;

  

   ClearPending(BIT_IIC);

       flag = 0;                //清标志

       led_toggle(2);

}

  

 

//AT24C02A页写,当sizeofdate为1时,是字节写

//输入参数依次为设备内存地址、IIC数据缓存数组和要写入的数据个数

void wr24c02a(char wordAddr, char *buffer,int len )

{

       int i;

   char mbuf[4];

   

   while(1) {

   i = rIICSTAT;

   if(i & (0x01<<5)){

      Uart_Send("bus busy",10);

      delay(100);

   } else

     break;

     }

   

       flag =1;                     //应答标志

       

       rIICDS = devAddr;

       rIICCON &= ~0x10;            //清中断标志

       rIICSTAT = 0xf0;             //主设备发送模式

       while(flag == 1)             //等待从设备应答,

              delay(100);           //一旦进入IIC中断,即可跳出该死循环

       Uart_Send("a",1); 

   

       flag = 1;

       rIICDS = wordAddr;            //写入从设备内存地址

       rIICCON &= ~0x10;

       while(flag)

              delay(100);

 

   Uart_Send("b",1);  

//连续写入数据

       for(i=0;i       {

              flag = 1;

              rIICDS = *(buffer+i);

              rIICCON &= ~0x10;

              while(flag)

                     delay(100);

  

  mbuf[0] = *(buffer + i);

  mbuf[1] = '.';

   Uart_Send(mbuf, 2);

       }

      

       rIICSTAT = 0xd0;         //发出stop命令,结束该次通讯

       rIICCON = 0xe0;          //为下次IIC通讯做准备

      

       delay(100);                   //等待

}

 

//AT24C02A的序列读,当sizeofdate为1时,是随机读

//输入参数依次为设备内存地址、IIC数据缓存数组和要读取的数据个数

void rd24c02a(char wordAddr,char *buffer,int len )

{

       int i;

       unsigned char temp;

   char mbuf[12];

   

   while(1) {

   i = rIICSTAT;

   if(i & (0x01<<5)){

      Uart_Send("bus busy",10);

      delay(100);

   } else

     break;

     }

   

       flag =1;

       rIICDS = devAddr ;                     //

       rIICCON &= ~0x10;            //清中断标志

       rIICSTAT = 0xf0;             //主设备发送模式

       while(flag)

推荐阅读

史海拾趣

海芯科技(AVIA)公司的发展小趣事

为了进一步拓展业务和提升公司的竞争力,海芯科技积极寻求与行业内外的合作伙伴建立战略合作关系。通过与上下游企业的紧密合作,海芯科技成功实现了产业链的整合和优化,进一步提升了产品的质量和性能。同时,公司还通过与国际知名企业的合作,将先进的技术和管理经验引入到公司内部,为公司的发展注入了新的活力。

德力康(DLK)公司的发展小趣事

随着电子行业的不断发展和变革,DLK公司也面临着转型升级的压力。为了适应市场需求的变化,DLK公司开始加快转型升级的步伐。一方面,公司加强了对新能源汽车、物联网等新兴领域的研究和开发;另一方面,公司积极探索智能制造、工业互联网等新技术在连接器生产中的应用。通过转型升级,DLK公司不仅提高了生产效率和产品质量,而且增强了企业的竞争力和可持续发展能力。

Coors Components Inc公司的发展小趣事

除了关注经济效益外,Coors Components Inc公司还积极履行社会责任。公司积极参与公益事业,为社会做出贡献;同时,公司也注重环保和可持续发展,努力降低生产过程中的环境污染。这些举措不仅提升了公司的品牌形象,还赢得了社会各界的广泛赞誉。

以上是关于电子行业公司发展的通用框架,你可以根据这些框架来进一步了解“Coors Components Inc”公司的具体发展故事。请注意,在编写故事时,应确保所描述的事实准确无误,避免夸大或缩小事实。

佰鸿(BrtLed)公司的发展小趣事

随着业务规模的不断扩大,佰鸿意识到提升产能效率的重要性。于是,公司在1990年转投资中国大陆兴建东莞高步厂,现有土地面积和厂房面积均达到相当规模,员工数量也增至数千人。这一举措极大地提升了佰鸿的生产能力,使其能够更好地满足市场需求,同时也为公司后续的发展提供了有力的支持。

American Technical Ceramics (ATC)公司的发展小趣事

佰鸿公司在2008年成立之初,正值LED行业蓬勃发展的时期。面对激烈的市场竞争,公司经过深入的市场调研,确立了LED大功率路灯制造商、方案提供商、系统集成商的市场定位。随后,佰鸿在大功率路灯照明市政LED改造方面投入大量精力,成功完成了兰池大道、咸阳快速干道等多个大型LED路灯方案设计及老旧路灯改造项目。这些项目的成功实施,不仅为佰鸿在市场上站稳了脚跟,也为其后续发展奠定了坚实的基础。

EPT公司的发展小趣事

EPT深知产品质量是企业发展的基石。因此,公司不仅通过了ISO9001:2015和BSCI等国际质量管理体系认证,还获得了CE、UL、IEC62133、KC等多项证书。此外,EPT还为所有电池购买了产品责任险,为客户提供双重保障。这一举措不仅提升了客户对EPT产品的信任度,也为其在电子行业中树立了良好的品牌形象。

问答坊 | AI 解惑

摄像头保存录像问题

    我现在是可以录像,把单个帧存成图片,我现在想保存录像存放在SD卡中,以后还要回调查阅的,有什么好的方法没?…

查看全部问答>

请问"禁能中断"的确切含义"

如果我禁能了一个中断源, 不论什么平台吧, ARM或51都无所谓. 那么当这个中断到来时, 中断标志位会被置上吗? \"禁能\"的意思究竟是中断标志位不会被置上, 还是说标志位会被置上, 但不会跳转到相应的处理函数? 如果被置上了, 我在什么时候清中断呢 ...…

查看全部问答>

使用USBD12开发

应用功能: 使用USB12开发一个USB设备,USB设备会产生记录(不定时),产生的记录需要及时发送到计算机 现在USBD12提供的上位机动态库为EasyUSB.dll,没有中断读取数据的方式,现在这种开发模式,上位机程序只能定时使用EasyUSB.dll的读取数据的函 ...…

查看全部问答>

文件指针

如何使用Zw形势的函数把文件指针移到文件末尾以实现追加写…

查看全部问答>

EVC有gridctrl这个控件吗?哪能下载到啊?

VC不自带这个控件,要下载.不知道EVC是否支持这个控件?…

查看全部问答>

ST以为自己是胡哥

问他们能否提供STM32 的FFT,调查了好几次。决定用TMS320F2808,FFT现成的,相关系列产品价格差不多,特别明年推出的TMS320F2802X和TMS320F2803X,性价比更好。他们最后一次:“我是问你要做什么产品,产品的市场是什么,另外我们也需要知 ...…

查看全部问答>

CodeSourcery免费吗

想了解下 如果把CodeSourcery的编译器嵌到软件中 随硬件卖给客户(软件算送) 这个犯法不?…

查看全部问答>

如何用T0输出两个不同的频率(先低频率,然后高频率)

      我用T0定时,输出两个不同的频率,先输出一个低点的频率,延时一段时间输出高点的频率,本来是想通过改变装不同的初值来实现输出不同的频率,但程序下载在单片机后,用示波器观察不正确,一直只有低的频率,不论等 ...…

查看全部问答>