ARM裸板开发:07_IIC 通过IIC总线接口读写时钟芯片时间参数实现的总结

问题一:程序直接在iRAM内部可正常执行,而程序搬移(Nand ->SDRAM)之后,就不能正常运行了

#define NAND_SECTOR_SIZE    2048

/* 读函数 */
void nand_read(unsigned char *buf, unsigned long start_addr, int size)
{
    int i, j;

//if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK))

    if (start_addr & NAND_BLOCK_MASK)
        return;    /* 地址不对齐则退出 */

    /* 选中芯片 */
    nand_select_chip();

    for(i=start_addr; i < (start_addr + size);)
    {
      /* 发出READ0命令 */
      write_cmd(0);
      /* Write Address */
      write_addr(i);
      write_cmd(0x30);

      /* 等待数据就绪 */
      wait_idle();

      for(j=0; j < NAND_SECTOR_SIZE; j++, i++)
      {
          *buf = read_data();
          buf++;
      }
    }

    /* 取消片选信号 */
    nand_disselect_chip();

    return;
}

查看韦东山nand_read代码,发现有这样一条语句:

if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK))

        return;    /* 地址或大小不对齐则退出 */

而在start.S中,size = __bss_start - 0x30000000,这个大小显然不能保证是2048的倍数(事实确也如此,并不是2048的倍数,也就导致了nand_read函数并未正常执行)

地址或大小不对齐则退出,这种方式有问题,大小确实也没必要对齐。若大小刚好超出一个块内存,就将这个块内存完整copy即可。

问题二:ARM9裸板开发过程,硬件并不不支持除法运算,所以除法以及取余操作如何实现?

/*
* val    : 需要转换的整形值
* bit    : 该整形值的位数
* pdst    : 转换字符串输出
*/
void int_to_str(int val, unsigned char bit, char *pdst)
{
    //根据val位数确定mult. E.G. val-1位 -> mult=1
    int mult;
    for (mult = 1; --bit != 0; mult *= 10);

    for ( ; mult != 0; mult /= 10)
    {
        *pdst++ = (char)(val/mult + ‘0‘);
        val %= mult;
    }
}

1、网上搜了一些方法,基本思想是运用移位运算,比较,以及乘法操作等实现。

比如:sum / 6    可转换为    sum * (1 / 6)    (1 / 6) -> (5461 / 32768),而 1/32768 即为(1 >> 15)。这种方法主要是通过将分数转换为被除数是2的次幂的方式实现的,有误差。

2、使用库函数。参考韦东山的方式,在07_IIC工程中添加includelib两个依赖库。同时修改对应地Makefile文件,可以正常编译通过。

#Time: 2018-4-19 11:56:52
#Proj: General Makefile
#Designed by DZH for JZ2440

#Define vars
TARGET_NAME    := iic
#final target
TARGET    := $(TARGET_NAME).bin
#temp target
BUILD    := $(TARGET_NAME).elf
#disa target
DISA    := $(TARGET_NAME).dis

#default boot from NAND Flash
ENV        ?= NAND

OBJS    += start.o
OBJS    += init.o
OBJS    += main.o
OBJS    += iic.o
OBJS    += nand.o
OBJS    += serial.o
OBJS    += m41t11.o
OBJS    += irq_handler.o
OBJS    += lib/libc.a

CROSS_COMPILE := arm-linux-
CC            := $(CROSS_COMPILE)gcc
LD            := $(CROSS_COMPILE)ld
AR          := $(CROSS_COMPILE)ar
OBJCOPY        := $(CROSS_COMPILE)objcopy
OBJDUMP        := $(CROSS_COMPILE)objdump

#warning
INCLUDEDIR     := $(shell pwd)/include
CCFLAGS    += -nostdinc -I$(INCLUDEDIR)
CCFLAGS    += -Wall -O2
# 不加-O2优化,链接过程报错:
# lib/libc.a(string.o)(.text+0x38): In function `puts‘:
# : undefined reference to `putc‘

#basic address
#ifeq ($(ENV), NAND)
#LDFLAGS    += -Ttext=0x0
#else
#LDFLAGS    += -Ttext=0xXXX
#endif
LDFLAGS    += -Tmap.lds

export     CC LD OBJCOPY OBJDUMP INCLUDEDIR CCFLAGS AR

#Compile way
all : $(DISA) $(TARGET)
$(DISA)    : $(BUILD)
    $(OBJDUMP) -D $^ > [email protected]

$(TARGET) : $(BUILD)
    $(OBJCOPY) -O binary -S $^ [email protected]

$(BUILD) : $(OBJS)
    $(LD) $(LDFLAGS) -o [email protected] $^

.PHONY : lib/libc.a
lib/libc.a:
    cd lib; make; cd ..

%.o : %.S
    $(CC) $(CCFLAGS) -c -o [email protected] $^
%.o : %.c
    $(CC) $(CCFLAGS) -c -o [email protected] $^

clean:
    make  clean -C lib
    rm -f $(TARGET) $(BUILD) $(DISA) *.o

其中加粗部分是为了将除法和取余运算的依赖库包含进来所执行的操作。

此外,为了实现时间参数的写入和读出,封装了几个有效的转换函数:

1、string -> int

/*
* pstr    : 字符串首地址,空字符结束
* len    : 字符串有效字符长度
*/
int str_to_int(const char *pstr, unsigned char len)
{
    unsigned int ret = 0;
    unsigned int mult;

    //根据pstr长度确定mult. E.G. pstr-1位 -> mult=1
    for (mult = 1; --len != 0; mult *= 10);

    for ( ;*pstr != ‘\0‘; ++pstr)
    {
        ret += (unsigned int)(*pstr - ‘0‘) * mult;
        mult /= 10;
    }

    return (int)ret;
}

 

2、int -> string

/*
* val    : 需要转换的整形值
* bit    : 该整形值的位数
* pdst    : 转换字符串输出
*/
void int_to_str(int val, unsigned char bit, char *pdst)
{
    //根据val位数确定mult. E.G. val-1位 -> mult=1
    int mult;
    for (mult = 1; --bit != 0; mult *= 10);

    for ( ; mult != 0; mult /= 10)
    {
        *pdst++ = (char)(val/mult + ‘0‘);
        val %= mult;
    }
}

3、参数设置时间参数结构体变量,将字符串类型的时间参数装换为对应的整形值

需要写入的时间参数格式:E.G.(year-mon-day-week-hour-min-sec): 2018 05 15 2 13 29 00,数值间以空格键分开

struct rtc_time {
    int tm_sec;
    int tm_min;
    int tm_hour;
    int tm_week;
    int tm_mday;
    int tm_mon;
    int tm_year;
};
void set_rtc_time(char *pstr, struct rtc_time *prtc)
{
    char *ptmp = pstr;
    char s_time[25];
    unsigned char i;
    unsigned char len[7] = {0};

    //1. 分拆时间字符串
    for ( i = 0; *ptmp != ‘\0‘;  ++ptmp)
    {
        if (*ptmp != ‘ ‘)
            len[i]++;
        else
        {
            *ptmp = ‘\0‘;
            ++i;
        }
    }

    //2. 设置对应rtc时间参数
    send_l(pstr);
    prtc->tm_year = str_to_int(pstr, len[0]);
    pstr += len[0] + 1;
    prtc->tm_mon = str_to_int(pstr, len[1]);
    pstr += len[1] + 1;
    prtc->tm_mday = str_to_int(pstr, len[2]);
    pstr += len[2] + 1;
    prtc->tm_week = str_to_int(pstr, len[3]);
    pstr += len[3] + 1;
    prtc->tm_hour = str_to_int(pstr, len[4]);
    pstr += len[4] + 1;
    prtc->tm_min = str_to_int(pstr, len[5]);
    pstr += len[5] + 1;
    prtc->tm_sec = str_to_int(pstr, len[6]);
}
void set_time(void)
{
    char s_time[30] = {0};
    send_l("E.G.(year-mon-day-week-hour-min-sec): 2018 5 15 2 13 29 0");
    recv_l(s_time);
    send_s("Input: ");
    send_l(s_time);
    set_rtc_time(s_time, &g_rtc_time);
    m41t11_set_datetime(&g_rtc_time);
}

由于时钟芯片m41t11可能不能正常工作(写入时间无效),故修改set_rtc_time函数作为测试函数如下

void set_rtc_time(char *pstr, struct rtc_time *prtc)
{
    char *ptmp = pstr;
    char s_time[25];
    unsigned char i;
    unsigned char len[7] = {0};

    //1. 分拆时间字符串
    for ( i = 0; *ptmp != ‘\0‘;  ++ptmp)
    {
        if (*ptmp != ‘ ‘)
            len[i]++;
        else
        {
            *ptmp = ‘\0‘;
            ++i;
        }
    }

    //2. 设置对应rtc时间参数
    send_l(pstr);
    prtc->tm_year = str_to_int(pstr, len[0]);
    pstr += len[0] + 1;
    send_l(pstr);
    prtc->tm_mon = str_to_int(pstr, len[1]);
    pstr += len[1] + 1;
    send_l(pstr);
    prtc->tm_mday = str_to_int(pstr, len[2]);
    pstr += len[2] + 1;
    send_l(pstr);
    prtc->tm_week = str_to_int(pstr, len[3]);
    pstr += len[3] + 1;
    send_l(pstr);
    prtc->tm_hour = str_to_int(pstr, len[4]);
    pstr += len[4] + 1;
    send_l(pstr);
    prtc->tm_min = str_to_int(pstr, len[5]);
    pstr += len[5] + 1;
    send_l(pstr);
    prtc->tm_sec = str_to_int(pstr, len[6]);
    get_rtc_time(&g_rtc_time, s_time);
    send_s("g_rtc_time: ");
    send_l(s_time);
}

3、读取时间参数结构体变量,并将其装换为字符串

void get_rtc_time(const struct rtc_time *prtc, char *pdst)
{
    //格式: 2018-05-15 2 19:30:00
    int_to_str(prtc->tm_year, 4, pdst);
    *(pdst+4) = ‘-‘;
    int_to_str(prtc->tm_mon, 2, pdst+5);
    *(pdst+7) = ‘-‘;
    int_to_str(prtc->tm_mday, 2, pdst+8);
    *(pdst+10) = ‘ ‘;
    int_to_str(prtc->tm_week, 1, pdst+11);
    *(pdst+12) = ‘ ‘;
    int_to_str(prtc->tm_hour, 2, pdst+13);
    *(pdst+15) = ‘:‘;
    int_to_str(prtc->tm_min, 2, pdst+16);
    *(pdst+18) = ‘:‘;
    int_to_str(prtc->tm_sec, 2, pdst+19);
    *(pdst+21) = ‘\0‘;
}

void show_time(void)
{
    //格式: 2018-05-15 2 13:29:00
    char s_time[25] = {0};
    send_s("Now is: ");
    m41t11_get_datetime(&g_rtc_time);
    get_rtc_time(&g_rtc_time, s_time);
    send_l(s_time);
}

最终实现的效果如下:

1、菜单界面

          

2、[R]ead  data&time.

            

3、[W]rite data&time.

      

从以上结果可以看出,int 与 string 之间的转换函数均可正常工作。

其中最后一行的 g_rtc_time 参数,是逆向转换后的输出结果,能够说明写入m41t11时钟芯片的参数没有问题

m41t11_set_datetime(&g_rtc_time);

不过之后读出的结果并没有发生改变:

      

故猜测可能是由于m41t11时钟芯片原因所致(不过纽扣电池电量不足应该可以排除,否则应该不能从中读出数据吧?这个并没有兴趣折腾了)

原文地址:https://www.cnblogs.com/Glory-D/p/9062245.html

时间: 2024-10-03 18:27:15

ARM裸板开发:07_IIC 通过IIC总线接口读写时钟芯片时间参数实现的总结的相关文章

arm 裸板开发 (1)

1,用汇编点亮led灯,并且写makefile文件 烧写实验 烧写过程: 首先我们需要了解4412的启动过程,可以看一下本人写的arm启动方式(不是很高大上,但是能看懂)啦啦啦啦 我们需要用到BL1 .BL2 引导文件.都将会在下面打包给出 利用SD卡,首先用SD_FLASH对SD卡进行分割. 然后挂载进vm root用户下命令:fdisk -l  查看磁盘情况,如图,我16G的卡被分割两个 进入sd_fuse 命令 ./fast_fuse.sh /dev/sdb      (注意一定要烧至分割

(转)IIC总线工作原理(1)

转载:http://www.eefocus.com/article/08-07/48416s.html图11-1给出一个由MCU作为主机,通过IIC总线带3个从机的单主机IIC总线系统.这是最常用.最典型的IIC总线连接方式. 物理结构上,IIC系统由一条串行数据线SDA和一条串行时钟线SCL组成.主机按一定的通信协议向从机寻址和进行信息 传输.在数据传输时,由主机初始化一次数据传输,主机使数据在SDA线上传输的同时还通过SCL线传输时钟.信息传输的对象和方向以及信息传输的开始和终 止均由主机决

【嵌入式开发】 嵌入式开发工具简介 (裸板调试示例 | 交叉工具链 | Makefile | 链接器脚本 | eclipse JLink 调试环境)

作者 : 韩曙亮 博客地址 : http://blog.csdn.net/shulianghan/article/details/42239705  参考博客 : [嵌入式开发]嵌入式 开发环境 (远程登录 | 文件共享 | NFS TFTP 服务器 | 串口连接 | Win8.1 + RedHat Enterprise 6.3 + Vmware11) 开发环境 : -- 操作系统 : Vmware11 + RedHat6.3 企业版 + Win8.1; -- 硬件 : OK-6410-A 开发

Exynos4412 IIC总线驱动开发(二)—— IIC 驱动开发

前面在Exynos4412 IIC总线驱动开发(一)-- IIC 基础概念及驱动架构分析 中学习了IIC驱动的架构,下面进入我们的驱动开发过程 首先看一张代码层次图,有助于我们的理解 上面这些代码的展示是告诉我们:linux内核和芯片提供商为我们的的驱动程序提供了 i2c驱动的框架,以及框架底层与硬件相关的代码的实现.  剩下的就是针对挂载在i2c两线上的i2c设备了device,而编写的即具体设备驱动了,这里的设备就是硬件接口外挂载的设备,而非硬件接口本身(soc硬件接口本身的驱动可以理解为总

Exynos4412 IIC总线驱动开发(一)—— IIC 基础概念及驱动架构分析

关于Exynos4412 IIC 裸机开发请看 :Exynos4412 裸机开发 -- IIC总线 ,下面回顾下 IIC 基础概念 一.IIC 基础概念 IIC(Inter-Integrated Circuit)总线是一种由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备.IIC总线产生于在80年代,最初为音频和视频设备开发,如今主要在服务器管理中使用,其中包括单个组件状态的通信.例如管理员可对各个组件进行查询,以管理系统的配置或掌握组件的功能状态,如电源和系统风扇.可随时监

从零开始写一个arm下的裸板程序

从零开始写一个arm下的裸板程序.我们整个程序是基于uboot运行的. 所有我们可以借助uboot中的printf来输出,默认开发版的标准输出是串口. 电脑的默认标准输出的屏幕. 1.需要创建的文件由include文件夹,用来存放头文件. 2.创建一个hw.h头文件. 3.编写一个common.h,它定义了借用uboot的printf的宏.和NULL这个宏的定义. 4.hw.c 硬件相关的文件. 5.main.c c文件. 6.start.s 汇编文件. 7.ld.lds 链接脚本, 8.Mak

刚接触开发板之烧写裸板程序

使用串口操作开发板的前提是开发板上已经有烧好的程序,因此开发板在没有烧好程序时,应先烧写程序.方法有: 1.使用并口工具烧写:接线(参考百问网JZ2440V2开发板使用手册),使用oflash烧写(速度比较慢),可烧写.bin文件,从新上电观察效果.可烧写u_boot. 2.使用openJTAG烧写,接线,使用oflash烧写(oflash烧写完后,会复位开发板). 3.使用Jlink烧写,请看如何烧写S3C2440裸板程序:JLink只支持烧写Nor Flash,不支持Nand Flash.要

S5PV210裸板驱动:启动

以往2440和6410的启动方式,只要我们把裸板代码烧写到NAND FLASH的开始位置,当开发板上点启动时,处理器会自动从NAND FLASH上拷贝前面一段的代码到内部的RAM中执行.按照以前的方法,我写了一段汇编代码,如下: 1_ARM/1_start/start.S 1 #define WTCON 0xE2700000 2 3 .text 4 .align 2 5 .global _start 6 7 _start: 8 //close the watchdog 9 ldr r1, =WT

i.MX8M系列开发板开发资料(米尔MYD-JX8MX)

1. i.MX8M开发板概述NXP 公司的 i.MX8M 系列的应用处理器基于 Arm? Cortex?-A53 和 Cortex-M4 内核, 具有业界领先的音频.语音和视频处理功能,适用于从消费家庭音频到工业楼宇自动化及移 动计算机等广泛应用. 作为 NXP 官方合作的设计公司,米尔电子推出了基 于 NXP 公司 i.MX8M 系列芯片的开发平台 MYD-JX8MX 系列开发板,以满足这一类高性能 产品的板卡要求.该开发板采用核心板加底板的形式, 提供了 HDMI,LVDS(或 MIPI).