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;
    }
}
一、網上搜了一些方法,基本思想是運用移位運算,比較,以及乘法操做等實現。
好比:sum / 6    可轉換爲    sum * (1 / 6)    (1 / 6) -> (5461 / 32768),而 1/32768 即爲(1 >> 15)。這種方法主要是經過將分數轉換爲被除數是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
其中加粗部分是爲了將除法和取餘運算的依賴庫包含進來所執行的操做。
 
此外,爲了實現時間參數的寫入和讀出,封裝了幾個有效的轉換函數:
一、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時鐘芯片緣由所致(不過鈕釦電池電量不足應該能夠排除,不然應該不能從中讀出數據吧?這個並無興趣折騰了)
相關文章
相關標籤/搜索