问题一:程序直接在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;
}
}
一、网上搜了一些方法,基本思想是运用移位运算,比较,以及乘法操做等实现。
好比:sum / 6 可转换为 sum * (1 / 6) (1 / 6) -> (5461 / 32768),而 1/32768 即为(1 >> 15)。这种方法主要是经过将分数转换为被除数是2的次幂的方式实现的,有偏差。
二、使用库函数。参考韦东山的方式,在07_IIC工程中添加
include和
lib两个依赖库。同时修改对应地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
其中加粗部分是为了将除法和取余运算的依赖库包含进来所执行的操做。
此外,为了实现时间参数的写入和读出,封装了几个有效的转换函数:
一、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;
}
二、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;
}
}
三、参数设置时间参数结构体变量,
将字符串类型的时间参数装换为对应的整形值
须要写入的时间参数格式: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);
}
三、读取时间参数结构体变量,并将其装换为字符串
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);
}
最终实现的效果以下:
一、菜单界面
二、[R]ead data&time.
三、[W]rite data&time.
从以上结果能够看出,int 与 string 之间的转换函数都可正常工做。
其中最后一行的 g_rtc_time 参数,是逆向转换后的输出结果,可以说明写入m41t11时钟芯片的参数没有问题
m41t11_set_datetime(&g_rtc_time);
不过以后读出的结果并无发生改变:
故猜想多是因为m41t11时钟芯片缘由所致(不过纽扣电池电量不足应该能够排除,不然应该不能从中读出数据吧?这个并无兴趣折腾了)