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 $^ > $@
 
$(TARGET) : $(BUILD)
    $(OBJCOPY) -O binary -S $^ $@
 
$(BUILD) : $(OBJS)
    $(LD) $(LDFLAGS) -o $@ $^
 
.PHONY : lib/libc.a
lib/libc.a:
    cd lib; make; cd ..
 
%.o : %.S
    $(CC) $(CCFLAGS) -c -o $@ $^
%.o : %.c
    $(CC) $(CCFLAGS) -c -o $@ $^
    
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 != '