ARM裸板開發:07_IIC 通過IIC總線接口讀寫時鐘芯片時間參數實現的總結
阿新 • • 發佈:2018-05-20
乘法 說明 ash from 庫函數 != 函數 lock 除法 問題一:程序直接在iRAM內部可正常執行,而程序搬移(Nand ->SDRAM)之後,就不能正常運行了
:ARM9裸板開發過程,硬件並不不支持除法運算,所以除法以及取余操作如何實現?
#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)查看韋東山nand_read代碼,發現有這樣一條語句: if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) return; /* 地址或大小不對齊則退出 */ 而在start.S中,size = __bss_start - 0x30000000,這個大小顯然不能保證是2048的倍數(事實確也如此,並不是2048的倍數,也就導致了nand_read函數並未正常執行) 地址或大小不對齊則退出,這種方式有問題,大小確實也沒必要對齊。若大小剛好超出一個塊內存,就將這個塊內存完整copy即可。 問題二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; }
/* * 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工程中添加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
其中加粗部分是為了將除法和取余運算的依賴庫包含進來所執行的操作。
此外,為了實現時間參數的寫入和讀出,封裝了幾個有效的轉換函數:
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時鐘芯片原因所致(不過紐扣電池電量不足應該可以排除,否則應該不能從中讀出數據吧?這個並沒有興趣折騰了)
ARM裸板開發:07_IIC 通過IIC總線接口讀寫時鐘芯片時間參數實現的總結