S5PV210裸机(五):定时器_s5pv210 rtc-程序员宅基地

技术标签: 汇编  c语言  arm开发  嵌入式硬件  

        本文主要探讨210定时器相关知识,210定时器主要包含PWN定时器,系统定时器,看门狗,RTC。

PWM定时器
        210有5个PWM定时器,timer0、1、2、3通过对应PIO产生PWM波形信号并输出,timer4没有GPIO只产生内部定时器中断
        PWM定时器时钟源为PCLK_PSYS,timer0、1共用prescaler0预分频器(8位),timer2、3、4使用prescaler1预分频器(8位),且每个timer有分频器预分频器和分频器构成分频系统,将PCLK_PSYS分频后的时钟给timer作为时钟周期
        预分频器分频值范围为1~256,分频器是MUX开关(1/1,1/2,1/4,1/8,1/16)
在PCLK_PSYS(66MHz)下,产生时钟周期范围为0.03us--62.061us,计数器TCNTB值范围为1--2^32,最大时间范围为266548.27s(74h+)

PWN配置寄存器TCFG0、TCFG1、TCON、TCNT、TCNTB、TCNTO、TCMPB

        TCFG0用于配置预分频器和死区 

         TCFG1用于配置分频器

        TCON用于配置自动重加载,手动刷入数据,时钟开关 

        TCNTB是地址寄存器(可写)用于存储计数值便于在自动模式下刷入

        TCNT(不可读写)用于周期递减(-1)将计数值写入TCNTB中,启动timer前需要将TCNTB中的值刷到TCNT中(手写寄存器输入一次)


TCNTO(只读)用于读取目前TCNT的值


PWM波形参数:周期T,占空比duty(高电平时间占比),TCMPB决定PWM波形占空比

电平翻转器
        电平翻转器是电平取反电路
        定义TCNT>TCMPB时为高电平,反之为低电平
        当占空比为30%翻转后变为70%(高低电平互换)

死区生成器
        PWM应对交流电压进行整流。整流时2路整流分别在正电平和负电平时导通工作,不能同时导通(短路)
        实际电路不可能同时上升或下降沿,保留留死区避免短路
        死区少容易短路,死区多控制精度低产品性能低
        210自带的死区生成器

蜂鸣器
        蜂鸣器的2金属片通电吸附撞击产生声音,通过导通频率控制吸附频率控制声音(PWM驱动)
        蜂鸣器通过GPD0_2(XpwmTOUT2)引脚连接在SoC
        GPD0CON(0xE02000A0),bit8~bit11设置为0b0010(TOUT_2是PWM输出)

看门狗定时器
        定时监测cpu防止跑飞,规定周期时间计数内若没有恢复计数,默认系统跑飞则会复位cpu
看门狗配置寄存器WTCON、WTDAT、WTCNT、WTCLRINT

        WTCON用于配置时钟源启停,时钟分频,中断启停,复位启停

         WTDAT配置第一次使用时间周期(上电到第一次触发的时间)   

         WTCNT配置时间周期的计数值               WTCLRINT写任意值清除中断  

实时时钟RTC
        RTC是内部外设,有独立晶振提供RTC时钟源(32.768KHz),内部的寄存器用来记录时间(年月日时分秒星期),系统关机时时间仍在计时(独立电源供电)

闹钟发生器定点时间产生RTC中断

RTC寄存器


INTP 中断挂起寄存器


RTCCON RTC控制寄存器


RTCALM    ALMxxx  闹钟功能有关的寄存器

BCDxxx           时间寄存器

BCD码
        27<==转换==>0x27
        RTC中所有的时间(年月日时分秒星期,闹钟)用BCD码编码

注意:RTC读写是禁止,读写前打开RTC,读写后关闭,读写RTC寄存器时,一定要注意BCD码和十进制之间的转换,BCDYEAR若2023写入(2023-2000)

demo1:

        PWN定时器操作蜂鸣器

        start.S

#define WTCON           0xE2700000
#define SVC_STACK       0xd0037d80

.global _start
.global IRQ_handler

_start:
        //close watchDog
        ldr r0,=WTCON
        ldr r1,=0x0
        str r1,[r0]

        //init SVC stack
        ldr sp,=SVC_STACK

        //init icache
        mrc p15,0,r0,c1,c0,0
        bic r0,r0,#(1<<12)      //close icache
        orr r0,r0,#(1<<12)      //open icache
        mcr p15,0,r0,c1,c0,0

        //use func
        bl main

main.c 

#include "pwn_buzzer.h"

static void dealy_time()
{
        volatile unsigned int i = 900000;
        while(i--);
}

int main()
{
        pwn_buzzer_timer_init();

        while(1)
        {
                dealy_time();
        }

        return 0;
}

 pwn_buzzer.h

void pwn_buzzer_timer_init();

 pwn_buzzer.c

#define GPD0CON         0xE02000A0

#define TCFG0           0xE2500000
#define TCFG1           0xE2500004
#define TCON            0xE2500008
#define TCNTB2          0xE2500024
#define TCMPB2          0xE2500028

#define rGPD0CON        (*(volatile unsigned int *) GPD0CON)
#define rTCFG0          (*(volatile unsigned int *) TCFG0)
#define rTCFG1          (*(volatile unsigned int *) TCFG1)
#define rTCON           (*(volatile unsigned int *) TCON)
#define rTCNTB0         (*(volatile unsigned int *) TCNTB2)
#define rTCMPB2         (*(volatile unsigned int *) TCMPB2)

void pwn_buzzer_timer_init()
{
        //set gpio as buzzer
        rGPD0CON &= ~(0x0f << 8);
        rGPD0CON |= (2 << 8);

        //set Prescaler as 65,real Prescaleris 66,Prescaler is 66Mhz /66 = 1Mhz
        rTCFG0 &= ~(0xff<<8);
        rTCFG0 = (65<<8);

        //set div ,set div is 2 that mean 1/2,so 1Mhz /2 = 500000hz = 2us
        rTCFG1 &= ~(0x0f<<8);
        rTCFG1 = (1<<8);

        //set TCON,set  Auto Reload open
        rTCON = (1<<15);

        //set TCNTB0,set the count of cycle
        //rTCNTB0 = time you need / set div 
        //ex: 1ms / 2us = 500
        rTCNTB0 = 500;

        //set TCMPB2,set the rate of duty,mean the rate of high and low level on all cycle 
        rTCMPB2 = 250;

        //set TCON,when firstly open timer that you Manual Refresh TCNTB0 to TCNT
        rTCON |= (1<<13);
        //after Manual Refresh,close Manual Refresh,then always Auto Reload
        rTCON &= ~(1<<13);

        //set TCON,open timer 
        rTCON |= (1<<12);
}

Makefile 

CC      =       arm-linux-gcc
LD      =       arm-linux-ld
OBJCOPY =       arm-linux-objcopy
OBJDUMP =       arm-linux-objdump
 
#预处理器的flag,flag就是编译器可选的选项
CPPFLAGS  := -nostdlib -nostdinc
#C编译器的flag
CFLAGS    := -Wall -O2 -fno-builtin
 
export CC LD OBJCOPY OBJDUMP CPPFLAGS CFLAGS
 
objs      := start.o main.o pwn_buzzer.o
 
led.bin:$(objs)
         $(LD) -Ttext 0x0  -o buzzer.elf $^
         $(OBJCOPY) -O binary buzzer.elf buzzer.bin
         $(OBJDUMP) -D buzzer.elf > buzzer.dis
         gcc mkv210.c -o mkv210
         ./mkv210 buzzer.bin sd.bin
 
%.o:%.S
         $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $< -c
 
%.o:%.c
         $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $< -c
 
clean:
         rm *.o *.elf *.bin *.dis mkv210 -f

demo2:

        看门狗中断

start.S

#define WTCON           0xE2700000
#define SVC_STACK       0xd0037d80
#define IRQ_STACK       0xd0037f80
 
.global _start
.global IRQ_handler
 
_start:
        //close watchDog
        ldr r0,=WTCON
        ldr r1,=0x0
        str r1,[r0]
 
        //init SVC stack
        ldr sp,=SVC_STACK
 
        //init icache
        mrc p15,0,r0,c1,c0,0
        bic r0,r0,#(1<<12)      //close icache
        orr r0,r0,#(1<<12)      //open icache
        mcr p15,0,r0,c1,c0,0
 
        //use func
        bl main
 
        b .
 
//all interrupt process:Protect the scene + mian iqr process + return scene
IRQ_handler:
        //init IRQ_STACK
        ldr sp, =IRQ_STACK
        //protect lr
        sub lr, lr, #4
        //protect r0--r12 that in irq stack
        stmfd sp!, {r0-r12, lr}
        //mian iqr process
        bl irq_handler
        //return scene
        ldmfd sp!, {r0-r12, pc}^

main.c 

#include "uart_printf.h"
#include "wdt_interrupt.h"
#include "stdio.h"
 
static void dealy_time()
{
        volatile unsigned int i = 1000000;
        while(i--);
}
 
int main()
{
        //init uart
        init_uart();
        printf("init uart over\n");
 
        //init outer interupt
        printf("init wdt\n");
        wdt_interrupt();
 
        //init inner interupt
        printf("init inner\n");
        init_inner_interrupt();
 
        //dealy time
        while(1)
        {
                printf("..");
                dealy_time();
        }
 
        return 0;
}

        uart_printf.h 

void init_uart();

      uart_printf.c

#define GPA0CON         0xE0200000
 
#define ULCON0          0xE2900000
#define UCON0           0xE2900004
#define UFCON0          0xE2900008
#define UMCON0          0xE290000C
#define UTRSTAT0        0xE2900010
#define UTXH0           0xE2900020
#define URXH0           0xE2900024
#define UBRDIV0         0xE2900028
#define UDIVSLOT0       0xE290002C
 
#define rGPA0CON        (*(volatile unsigned int *)GPA0CON)
#define rULCON0         (*(volatile unsigned int *)ULCON0)
#define rUCON0          (*(volatile unsigned int *)UCON0)
#define rUFCON0         (*(volatile unsigned int *)UFCON0)
#define rUMCON0         (*(volatile unsigned int *)UMCON0)
#define rUTRSTAT0       (*(volatile unsigned int *)UTRSTAT0)
#define rUTXH0          (*(volatile unsigned int *)UTXH0)
#define rURXH0          (*(volatile unsigned int *)URXH0)
#define rUBRDIV0        (*(volatile unsigned int *)UBRDIV0)
#define rUDIVSLOT0      (*(volatile unsigned int *)UDIVSLOT0)
 
//init uart
void init_uart()
{
        //set gpio as uart(rx,tx)
        rGPA0CON &= ~(0xff);
        rGPA0CON |= ((1<<2)|(1<<5));
 
        //set uart base configure(mode)
        rULCON0 = 0x3;
        rUCON0 = 0x5;
        rUMCON0 = 0;
        rUFCON0 = 0;
 
        //set uart baud
        //DIV_VAL = (PCLK / (bps x 16))-1
        //(66000000 /(115200 * 16)) -1 = 34.8
        rUBRDIV0 = 34;
 
        //set uart baud calibration
        //0.8 * 16 = 13,check 210 table
        rUDIVSLOT0 = 0xdfdd;
}
 
 
//send data
void putc(char data)
{                  
        while (!(rUTRSTAT0 & (1<<1)));
        rUTXH0 = data;
}
 
//receive data
char getc()
{
        while (!(rUTRSTAT0 & (1<<0)));
        return (rURXH0 & 0xff);
}

        wdt_interrupt.h 

void wdt_interrupt();
 
void init_inner_interrupt()

        wdt_interrupt.c

   

#include "stdio.h"
 
//watchDog interrupt register

#define WTCON           0xE2700000
#define WTDAT           0xE2700004
#define WTCNT           0xE2700008
#define WTCLRINT         0xE270000C

#define rWTCON          *((volatile unsigned int *) WTCON)
#define rWTDAT          *((volatile unsigned int *) WTDAT)
#define rWTCNT          *((volatile unsigned int *) WTCNT)
#define rWTCLRINT         *((volatile unsigned int *) WTCLRINT)

//inner interrupt register
 
//VIC base address
 
#define VIC0_BASE       0xF2000000
#define VIC1_BASE       0xF2100000
#define VIC2_BASE       0xF2200000
#define VIC3_BASE       0xF2300000
 
//VIC0 register
 
#define rVIC0IRQSTATUS          (*(volatile unsigned int *)(VIC0_BASE + 0x0000))
#define rVIC0FIQSTATUS          (*(volatile unsigned int *)(VIC0_BASE + 0x0004))
#define rVIC0INTSELECT          (*(volatile unsigned int *)(VIC0_BASE + 0x000C))
#define rVIC0INTENABLE          (*(volatile unsigned int *)(VIC0_BASE + 0x0010))
#define rVIC0INTENCLEAR         (*(volatile unsigned int *)(VIC0_BASE + 0x0014))
#define rVIC0VECTADDR           (VIC0_BASE + 0x100)
#define rVIC0ADDRESS            (*(volatile unsigned int *)(VIC0_BASE + 0x0F00))
 
//VIC1 register
 
#define rVIC1IRQSTATUS          (*(volatile unsigned int *)(VIC1_BASE + 0x0000))
#define rVIC1FIQSTATUS          (*(volatile unsigned int *)(VIC1_BASE + 0x0004))
#define rVIC1INTSELECT          (*(volatile unsigned int *)(VIC1_BASE + 0x000C))
#define rVIC1INTENABLE          (*(volatile unsigned int *)(VIC1_BASE + 0x0010))
#define rVIC1INTENCLEAR         (*(volatile unsigned int *)(VIC1_BASE + 0x0014))
#define rVIC1VECTADDR           (VIC1_BASE + 0x100)
#define rVIC1ADDRESS            (*(volatile unsigned int *)(VIC1_BASE + 0x0F00))
 
//VIC2 register
 
#define rVIC2IRQSTATUS          (*(volatile unsigned int *)(VIC2_BASE + 0x0000))
#define rVIC2FIQSTATUS          (*(volatile unsigned int *)(VIC2_BASE + 0x0004))
#define rVIC2INTSELECT          (*(volatile unsigned int *)(VIC2_BASE + 0x000C))
#define rVIC2INTENABLE          (*(volatile unsigned int *)(VIC2_BASE + 0x0010))
#define rVIC2INTENCLEAR         (*(volatile unsigned int *)(VIC2_BASE + 0x0014))
#define rVIC2VECTADDR           (VIC2_BASE + 0x100)
#define rVIC2ADDRESS            (*(volatile unsigned int *)(VIC2_BASE + 0x0F00))
 
//VIC3 register
 
#define rVIC3IRQSTATUS          (*(volatile unsigned int *)(VIC3_BASE + 0x0000))
#define rVIC3FIQSTATUS          (*(volatile unsigned int *)(VIC3_BASE + 0x0004))
#define rVIC3INTSELECT          (*(volatile unsigned int *)(VIC3_BASE + 0x000C))
#define rVIC3INTENABLE          (*(volatile unsigned int *)(VIC3_BASE + 0x0010))
#define rVIC3INTENCLEAR         (*(volatile unsigned int *)(VIC3_BASE + 0x0014))
#define rVIC3VECTADDR           (VIC3_BASE + 0x100)
#define rVIC3ADDRESS            (*(volatile unsigned int *)(VIC3_BASE + 0x0F00))
 
//interrupt vector table
 
#define vector_table_base       0xD0037400
 
#define reset_vector            (vector_table_base + 0x00)
#define undef_vector            (vector_table_base + 0x04)
#define sotf_interrupt_vector   (vector_table_base + 0x08)
#define prefetch_vector         (vector_table_base + 0x0C)
#define data_vector             (vector_table_base + 0x10)
#define irq_vector              (vector_table_base + 0x18)
#define fiq_vector              (vector_table_base + 0x1C)
 
#define r_reset_vector                  (*(volatile unsigned int *) reset_vector)
#define r_undef_vector                  (*(volatile unsigned int *) undef_vector)
#define r_sotf_interrupt_vector         (*(volatile unsigned int *) sotf_interrupt_vector)
#define r_prefetch_vector               (*(volatile unsigned int *) prefetch_vector)
#define r_data_vector                   (*(volatile unsigned int *) data_vector)
#define r_irq_vector                    (*(volatile unsigned int *) irq_vector)
#define r_fiq_vector                    (*(volatile unsigned int *) fiq_vector)
 
//interrupt number
 
#define NUM_TIMER0                              (21)
#define NUM_TIMER1                              (22)
#define NUM_TIMER2                              (23)
#define NUM_TIMER3                              (24)
#define NUM_TIMER4                              (25)
#define NUM_SYSTIMER                            (26)
#define NUM_WDT                                 (27)
#define NUM_RTC_ALARM                           (28)
#define NUM_RTC_TICK                            (29)

//wdt interrupt func

void wdt_interrupt()
{
        //set WTCON,set Prescaler,Prescaler is set value + 1
        //Prescaler = 65 + 1 = 66,66Mhz / 66 = 1Mhz = 1000000hz
        rWTCON &= ~(0xff << 8); 
        rWTCON |= (65<<8);
        //set div is 128,t = 1/(1000000hz /128) = 1.28us
        rWTCON &= ~(3 << 3);
        rWTCON |= (3<<3);

        //set WTCON,open interrupt and close reset
        rWTCON |= (1<<2);
        rWTCON &= ~(1);

        //set WTDAT,set set the time form firstly open timer to count open(WTCNT)
        rWTDAT = 1000;
        rWTCNT = 1000;

        //open wdt
        rWTCON |= (1<<5);
}
 
//dealy_time
 
static void dealy_time()
{
        volatile unsigned int i = 1000000;
        while(i--);
}
 
 
//outer interrupt key func
static void isr_wdt()
{
        static int num = 0;
        printf("wdt interrupt,num = %d\n",num++);
        dealy_time();

        //clear VIC0ADDR,clear using interrupt process
        rVIC0ADDRESS = 0;
        rVIC1ADDRESS = 0;
        rVIC2ADDRESS = 0;
        rVIC3ADDRESS = 0;

        rWTCLRINT = 1;  
}
 
//inner interrupt func
 
static void reset_func()
{
        printf("reset\n");
}
 
static void undef_func()
{
        printf("undef\n");
}
 
static void sotf_interrupt_func()
 
{
        printf("sotf_intrrupt\n");
}
 
static void prefetch_func()
{
        printf("prefetch\n");
}
 
static void data_func()
{
        printf("data\n");
}
 
static void fiq_func()
{
        printf("irq\n");
}
 
void IRQ_handler();
 
static void bind_isr_VICnINTENCLEAR(unsigned long num,void (*handler)())
{
        if(num <32)
        {
                printf("bind ok\n");
                *((volatile unsigned int *)(rVIC0VECTADDR + 4 * (num))) = (unsigned)handler;
        }
        else if(num < 64)
        {
                *((volatile unsigned int *)(rVIC0VECTADDR + 4 * (num-32))) = (unsigned)handler;
        }
        else if(num < 96)
        {
                *((volatile unsigned int *)(rVIC0VECTADDR + 4 * (num-64))) = (unsigned)handler;
        }
        else
        {
                *((volatile unsigned int *)(rVIC0VECTADDR + 4 * (num-96))) = (unsigned)handler;
        }
}
 
static void enable_interrupt(unsigned long num)
{
        unsigned long tmp;
 
        if(num < 32)
        {
                tmp = rVIC0INTENABLE;
                tmp |= (1<<num);
                rVIC0INTENABLE = tmp;
        }
        else if(num < 64)
        {
                tmp = rVIC0INTENABLE;
                tmp |= (1<<(num-32));
                rVIC1INTENABLE = tmp;
        }
        else if(num < 96)
        {
                tmp = rVIC0INTENABLE;
                tmp |= (1<<(num-64));
                rVIC2INTENABLE = tmp;
        }
        else if(num < 200)
        {
                tmp = rVIC0INTENABLE;
                tmp |= (1<<(num-96));
                rVIC3INTENABLE = tmp;
        }
        else
        {
                rVIC0INTENABLE = 0xffffffff;
                rVIC1INTENABLE = 0xffffffff;
                rVIC2INTENABLE = 0xffffffff;
                rVIC3INTENABLE = 0xffffffff;
        }
}
 
void init_inner_interrupt()
{
        //bind interrupt process on interrupt vector table 
        r_reset_vector           =      (unsigned int)reset_func; 
        r_undef_vector           =      (unsigned int)undef_func;
        r_sotf_interrupt_vector  =      (unsigned int)sotf_interrupt_func;
        r_prefetch_vector        =      (unsigned int)prefetch_func;
        r_data_vector            =      (unsigned int)data_func;
        r_irq_vector             =      (unsigned int)IRQ_handler;
        r_fiq_vector             =      (unsigned int)fiq_func;
 
        //select interrupt mode(irq)
        rVIC0INTSELECT = 0x0;
        rVIC1INTSELECT = 0x0;
        rVIC2INTSELECT = 0x0;
        rVIC3INTSELECT = 0x0;
 
        //diasble interrupt
        rVIC0INTENCLEAR = 0xffffffff;
        rVIC1INTENCLEAR = 0xffffffff;
        rVIC2INTENCLEAR = 0xffffffff;
        rVIC3INTENCLEAR = 0xffffffff;
 
        //clear interrupt process address 
        rVIC0ADDRESS = 0;
        rVIC1ADDRESS = 0;
        rVIC2ADDRESS = 0;
        rVIC3ADDRESS = 0;
 
        //bind isr process on VICnINTENCLEAR
        bind_isr_VICnINTENCLEAR(NUM_WDT,isr_wdt);
 
        //enable interrupt
        enable_interrupt(NUM_WDT);
}
 
//judge inner interrupt ,get interrupt occure in which VICnVECTADDR
void irq_handler()
{
        volatile unsigned int n = 0;
        void (*isr)(void) = NULL;
        for(n = 0;n <4;n++)
        {
                if(n == 0 && rVIC0IRQSTATUS != 0)
                {
                        isr = (void (*)(void))rVIC0ADDRESS; 
                }
                else if(n == 1 && rVIC1IRQSTATUS != 0)
                {
                        isr = (void (*)(void))rVIC1ADDRESS; 
                }
                else if(n == 2 && rVIC2IRQSTATUS != 0)
                {
                        isr = (void (*)(void))rVIC2ADDRESS; 
                }
                else if(n == 3 && rVIC3IRQSTATUS != 0)
                {
                        isr = (void (*)(void))rVIC3ADDRESS; 
                }
                (*isr)();
        }
}

        link.lds

SECTIONS
{
        . = 0xd0020010;
 
        .text :
        {
                start.o
                *(.text)
        }
 
        .data :
        {
                *(.data)
        }
 
        .bss :
        {
                *(.bss)
        }
}

         Makefile

CC      =       arm-linux-gcc
LD      =       arm-linux-ld
OBJCOPY =       arm-linux-objcopy
OBJDUMP =       arm-linux-objdump
 
INCDIR  := $(shell pwd)
 
#预处理器的flag,flag就是编译器可选的选项
CPPFLAGS  := -nostdlib -nostdinc -I$(INCDIR)/include
#C编译器的flag
CFLAGS    := -Wall -O2 -fno-builtin
 
export CC LD OBJCOPY OBJDUMP CPPFLAGS CFLAGS
 
objs      := start.o uart_printf.o main.o wdt_interrupt.o
objs      += lib/libc.a
 
led.bin:$(objs)
        $(LD) -Tlink.lds -o wdt_interrupt.elf $^
        $(OBJCOPY) -O binary wdt_interrupt.elf wdt_interrupt.bin
        $(OBJDUMP) -D wdt_interrupt.elf > wdt_interrupt.dis
        gcc mkv210.c -o mkv210
        ./mkv210 wdt_interrupt.bin sd.bin
 
lib/libc.a:
        cd lib;  make;  cd ..
 
%.o:%.S
        $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $< -c
 
%.o:%.c
        $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $< -c
 
clean:
        rm *.o *.elf *.bin *.dis mkv210 -f
        cd lib; make clean; cd ..

        结果示例:  

demo3:

        看门狗复位

        start.S

#define WTCON           0xE2700000
#define SVC_STACK       0xd0037d80
 
.global _start
.global IRQ_handler
 
_start:
        //close watchDog
        ldr r0,=WTCON
        ldr r1,=0x0
        str r1,[r0]
 
        //init SVC stack
        ldr sp,=SVC_STACK
 
        //init icache
        mrc p15,0,r0,c1,c0,0
        bic r0,r0,#(1<<12)      //close icache
        orr r0,r0,#(1<<12)      //open icache
        mcr p15,0,r0,c1,c0,0
 
        //use func
        bl main
 
        b .

           main.c

#include "uart_printf.h"
#include "wdt_reset.h"
#include "stdio.h"
 
static void dealy_time()
{
        volatile unsigned int i = 1000000;
        while(i--);
}
 
int main()
{
        //init uart
        init_uart();
        printf("init uart over\n");
 
        //init outer interupt
        static int num = 1;
        printf("init wdt,num = %d\n",num++);
        wdt_reset();

        //dealy_time 
        while(1)
        {
                dealy_time();

        }
 
        return 0;
}

          uart_printf.h 

void init_uart();

         uart_printf.c

#define GPA0CON         0xE0200000
 
#define ULCON0          0xE2900000
#define UCON0           0xE2900004
#define UFCON0          0xE2900008
#define UMCON0          0xE290000C
#define UTRSTAT0        0xE2900010
#define UTXH0           0xE2900020
#define URXH0           0xE2900024
#define UBRDIV0         0xE2900028
#define UDIVSLOT0       0xE290002C
 
#define rGPA0CON        (*(volatile unsigned int *)GPA0CON)
#define rULCON0         (*(volatile unsigned int *)ULCON0)
#define rUCON0          (*(volatile unsigned int *)UCON0)
#define rUFCON0         (*(volatile unsigned int *)UFCON0)
#define rUMCON0         (*(volatile unsigned int *)UMCON0)
#define rUTRSTAT0       (*(volatile unsigned int *)UTRSTAT0)
#define rUTXH0          (*(volatile unsigned int *)UTXH0)
#define rURXH0          (*(volatile unsigned int *)URXH0)
#define rUBRDIV0        (*(volatile unsigned int *)UBRDIV0)
#define rUDIVSLOT0      (*(volatile unsigned int *)UDIVSLOT0)
 
//init uart
void init_uart()
{
        //set gpio as uart(rx,tx)
        rGPA0CON &= ~(0xff);
        rGPA0CON |= ((1<<2)|(1<<5));
 
        //set uart base configure(mode)
        rULCON0 = 0x3;
        rUCON0 = 0x5;
        rUMCON0 = 0;
        rUFCON0 = 0;
 
        //set uart baud
        //DIV_VAL = (PCLK / (bps x 16))-1
        //(66000000 /(115200 * 16)) -1 = 34.8
        rUBRDIV0 = 34;
 
        //set uart baud calibration
        //0.8 * 16 = 13,check 210 table
        rUDIVSLOT0 = 0xdfdd;
}
 
 
//send data
void putc(char data)
{                  
        while (!(rUTRSTAT0 & (1<<1)));
        rUTXH0 = data;
}
 
//receive data
char getc()
{
        while (!(rUTRSTAT0 & (1<<0)));
        return (rURXH0 & 0xff);
}

        wdt_reset.h 

void wdt_reset();

        wdt_reset.c

#define WTCON           0xE2700000
#define WTDAT           0xE2700004
#define WTCNT           0xE2700008
#define WTCLRIN         0xE270000C

#define rWTCON          *((volatile unsigned int *) WTCON)
#define rWTDAT          *((volatile unsigned int *) WTDAT)
#define rWTCNT          *((volatile unsigned int *) WTCNT)
#define rWTCLRI         *((volatile unsigned int *) WTCLRI)

void wdt_reset()
{
        //set WTCON,set Prescaler,Prescaler is set value + 1
        //Prescaler = 65 + 1 = 66,66Mhz / 66 = 1Mhz = 1000000hz
        rWTCON &= ~(0xff << 8); 
        rWTCON |= (65<<8);
        //set div is 128,t = 1/(1000000hz /128) = 1.28us
        rWTCON &= ~(3 << 3);
        rWTCON |= (3<<8);

        //set WTCON,close interrupt and open reset
        rWTCON &= ~(1<<2);
        rWTCON |= 1;

        //set WTDAT,set set the time form firstly open timer to count open(WTCNT)
        rWTDAT = 1000;
        rWTCNT = 1000;

        //open wdt
        rWTCON |= (1<<5);
}

        link.lds 

SECTIONS
{
        . = 0xd0020010;
 
        .text :
        {
                start.o
                *(.text)
        }
 
        .data :
        {
                *(.data)
        }
 
        .bss :
        {
                *(.bss)
        }
}

        Makefile 

CC      =       arm-linux-gcc
LD      =       arm-linux-ld
OBJCOPY =       arm-linux-objcopy
OBJDUMP =       arm-linux-objdump
 
INCDIR  := $(shell pwd)
 
#预处理器的flag,flag就是编译器可选的选项
CPPFLAGS  := -nostdlib -nostdinc -I$(INCDIR)/include
#C编译器的flag
CFLAGS    := -Wall -O2 -fno-builtin
 
export CC LD OBJCOPY OBJDUMP CPPFLAGS CFLAGS
 
objs      := start.o uart_printf.o main.o wdt_reset.o
objs      += lib/libc.a
 
led.bin:$(objs)
        $(LD) -Tlink.lds -o wdt_reset.elf $^
        $(OBJCOPY) -O binary wdt_reset.elf wdt_reset.bin
        $(OBJDUMP) -D wdt_reset.elf > wdt_reset.dis
        gcc mkv210.c -o mkv210
        ./mkv210 wdt_reset.bin sd.bin
 
lib/libc.a:
        cd lib;  make;  cd ..
 
%.o:%.S
        $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $< -c
 
%.o:%.c
        $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $< -c
 
clean:
        rm *.o *.elf *.bin *.dis mkv210 -f
        cd lib; make clean; cd ..

        结果示例: 

demo4:

        中断(alarm)读写RTC

        start.S

#define WTCON           0xE2700000
#define SVC_STACK       0xd0037d80
#define IRQ_STACK       0xd0037f80
 
.global _start
.global IRQ_handler
 
_start:
        //close watchDog
        ldr r0,=WTCON
        ldr r1,=0x0
        str r1,[r0]
 
        //init SVC stack
        ldr sp,=SVC_STACK
 
        //init icache
        mrc p15,0,r0,c1,c0,0
        bic r0,r0,#(1<<12)      //close icache
        orr r0,r0,#(1<<12)      //open icache
        mcr p15,0,r0,c1,c0,0
 
        //use func
        bl main
 
        b .
 
//all interrupt process:Protect the scene + mian iqr process + return scene
IRQ_handler:
        //init IRQ_STACK
        ldr sp, =IRQ_STACK
        //protect lr
        sub lr, lr, #4
        //protect r0--r12 that in irq stack
        stmfd sp!, {r0-r12, lr}
        //mian iqr process
        bl irq_handler
        //return scene
        ldmfd sp!, {r0-r12, pc}^

        main.c  

#include "uart_printf.h"
#include "rtc_alarm.h"
#include "stdio.h"
 
static void dealy_time()
{
        volatile unsigned int i,j;
        for (i=0; i<10000; i++)
                        for (j=0; j<1000; j++);
}
 
int main()
{
        //init uart
        init_uart();
        printf("init uart over\n");

        //init outer interupt
         printf("rtc init\n");
        rtc_alarm();

        //set RTC time
        struct rtc_time rtc_write = 
        {
                .year = 2023,
                .month = 10,
                .date = 22,
                .hour = 14,
                .minute = 00,
                .second = 00,
                .day = 0,
        };

        set_rtc_time(&rtc_write);

        //init inner interupt
        printf("init inner\n");
        init_inner_interrupt();

        struct rtc_time rtc_read;

        //dealy time
        while(1)
        {
                get_rtc_time(&rtc_read);
                printf("rtc time:%d-%d-%d--%d %d:%d:%d\n", rtc_read.year,rtc_read.month,rtc_read.date,rtc_read.day,rtc_read.hour,rtc_read.minute,rtc_read.second);
                dealy_time();
        }

        while(1); 
        return 0;
}

        uart_printf.h 

void init_uart();

         uart_printf.c

#define GPA0CON         0xE0200000
 
#define ULCON0          0xE2900000
#define UCON0           0xE2900004
#define UFCON0          0xE2900008
#define UMCON0          0xE290000C
#define UTRSTAT0        0xE2900010
#define UTXH0           0xE2900020
#define URXH0           0xE2900024
#define UBRDIV0         0xE2900028
#define UDIVSLOT0       0xE290002C
 
#define rGPA0CON        (*(volatile unsigned int *)GPA0CON)
#define rULCON0         (*(volatile unsigned int *)ULCON0)
#define rUCON0          (*(volatile unsigned int *)UCON0)
#define rUFCON0         (*(volatile unsigned int *)UFCON0)
#define rUMCON0         (*(volatile unsigned int *)UMCON0)
#define rUTRSTAT0       (*(volatile unsigned int *)UTRSTAT0)
#define rUTXH0          (*(volatile unsigned int *)UTXH0)
#define rURXH0          (*(volatile unsigned int *)URXH0)
#define rUBRDIV0        (*(volatile unsigned int *)UBRDIV0)
#define rUDIVSLOT0      (*(volatile unsigned int *)UDIVSLOT0)
 
//init uart
void init_uart()
{
        //set gpio as uart(rx,tx)
        rGPA0CON &= ~(0xff);
        rGPA0CON |= ((1<<2)|(1<<5));
 
        //set uart base configure(mode)
        rULCON0 = 0x3;
        rUCON0 = 0x5;
        rUMCON0 = 0;
        rUFCON0 = 0;
 
        //set uart baud
        //DIV_VAL = (PCLK / (bps x 16))-1
        //(66000000 /(115200 * 16)) -1 = 34.8
        rUBRDIV0 = 34;
 
        //set uart baud calibration
        //0.8 * 16 = 13,check 210 table
        rUDIVSLOT0 = 0xdfdd;
}
 
 
//send data
void putc(char data)
{                  
        while (!(rUTRSTAT0 & (1<<1)));
        rUTXH0 = data;
}
 
//receive data
char getc()
{
        while (!(rUTRSTAT0 & (1<<0)));
        return (rURXH0 & 0xff);
}

  rtc_struct.h      

struct rtc_time
{
        unsigned int year;
        unsigned int month;
        unsigned int date;                      //几号
        unsigned int hour;
        unsigned int minute;
        unsigned int second;
        unsigned int day;                       //星期
};

         rtc_alarm.h

#include "rtc_struct.h"

void rtc_alarm();

void set_rtc_time(struct rtc_time  *p);

void get_rtc_time(struct rtc_time  *p);
 
void init_inner_interrupt();

        rtc_alarm.c

#include "stdio.h"
#include "rtc_struct.h"
 
//rtc interrupt register

#define RTC_BASE        0xE2800000

#define         rINTP            (*((volatile unsigned long *)(RTC_BASE + 0x30)))
#define         rRTCCON          (*((volatile unsigned long *)(RTC_BASE + 0x40)))
#define         rTICCNT          (*((volatile unsigned long *)(RTC_BASE + 0x44)))
#define         rRTCALM          (*((volatile unsigned long *)(RTC_BASE + 0x50)))
#define         rALMSEC          (*((volatile unsigned long *)(RTC_BASE + 0x54)))
#define         rALMMIN          (*((volatile unsigned long *)(RTC_BASE + 0x58)))
#define         rALMHOUR         (*((volatile unsigned long *)(RTC_BASE + 0x5c)))
#define         rALMDATE         (*((volatile unsigned long *)(RTC_BASE + 0x60)))
#define         rALMMON          (*((volatile unsigned long *)(RTC_BASE + 0x64)))
#define         rALMYEAR         (*((volatile unsigned long *)(RTC_BASE + 0x68)))
#define         rRTCRST          (*((volatile unsigned long *)(RTC_BASE + 0x6c)))
#define         rBCDSEC          (*((volatile unsigned long *)(RTC_BASE + 0x70)))
#define         rBCDMIN          (*((volatile unsigned long *)(RTC_BASE + 0x74)))
#define         rBCDHOUR         (*((volatile unsigned long *)(RTC_BASE + 0x78)))
#define         rBCDDATE         (*((volatile unsigned long *)(RTC_BASE + 0x7c)))
#define         rBCDDAY          (*((volatile unsigned long *)(RTC_BASE + 0x80)))
#define         rBCDMON          (*((volatile unsigned long *)(RTC_BASE + 0x84)))
#define         rBCDYEAR         (*((volatile unsigned long *)(RTC_BASE + 0x88)))
#define         rCURTICCNT       (*((volatile unsigned long *)(RTC_BASE + 0x90)))
#define         rRTCLVD          (*((volatile unsigned long *)(RTC_BASE + 0x94)))

//inner interrupt register
 
//VIC base address
 
#define VIC0_BASE       0xF2000000
#define VIC1_BASE       0xF2100000
#define VIC2_BASE       0xF2200000
#define VIC3_BASE       0xF2300000
 
//VIC0 register
 
#define rVIC0IRQSTATUS          (*(volatile unsigned int *)(VIC0_BASE + 0x0000))
#define rVIC0FIQSTATUS          (*(volatile unsigned int *)(VIC0_BASE + 0x0004))
#define rVIC0INTSELECT          (*(volatile unsigned int *)(VIC0_BASE + 0x000C))
#define rVIC0INTENABLE          (*(volatile unsigned int *)(VIC0_BASE + 0x0010))
#define rVIC0INTENCLEAR         (*(volatile unsigned int *)(VIC0_BASE + 0x0014))
#define rVIC0VECTADDR           (VIC0_BASE + 0x100)
#define rVIC0ADDRESS            (*(volatile unsigned int *)(VIC0_BASE + 0x0F00))
 
//VIC1 register
 
#define rVIC1IRQSTATUS          (*(volatile unsigned int *)(VIC1_BASE + 0x0000))
#define rVIC1FIQSTATUS          (*(volatile unsigned int *)(VIC1_BASE + 0x0004))
#define rVIC1INTSELECT          (*(volatile unsigned int *)(VIC1_BASE + 0x000C))
#define rVIC1INTENABLE          (*(volatile unsigned int *)(VIC1_BASE + 0x0010))
#define rVIC1INTENCLEAR         (*(volatile unsigned int *)(VIC1_BASE + 0x0014))
#define rVIC1VECTADDR           (VIC1_BASE + 0x100)
#define rVIC1ADDRESS            (*(volatile unsigned int *)(VIC1_BASE + 0x0F00))
 
//VIC2 register
 
#define rVIC2IRQSTATUS          (*(volatile unsigned int *)(VIC2_BASE + 0x0000))
#define rVIC2FIQSTATUS          (*(volatile unsigned int *)(VIC2_BASE + 0x0004))
#define rVIC2INTSELECT          (*(volatile unsigned int *)(VIC2_BASE + 0x000C))
#define rVIC2INTENABLE          (*(volatile unsigned int *)(VIC2_BASE + 0x0010))
#define rVIC2INTENCLEAR         (*(volatile unsigned int *)(VIC2_BASE + 0x0014))
#define rVIC2VECTADDR           (VIC2_BASE + 0x100)
#define rVIC2ADDRESS            (*(volatile unsigned int *)(VIC2_BASE + 0x0F00))
 
//VIC3 register
 
#define rVIC3IRQSTATUS          (*(volatile unsigned int *)(VIC3_BASE + 0x0000))
#define rVIC3FIQSTATUS          (*(volatile unsigned int *)(VIC3_BASE + 0x0004))
#define rVIC3INTSELECT          (*(volatile unsigned int *)(VIC3_BASE + 0x000C))
#define rVIC3INTENABLE          (*(volatile unsigned int *)(VIC3_BASE + 0x0010))
#define rVIC3INTENCLEAR         (*(volatile unsigned int *)(VIC3_BASE + 0x0014))
#define rVIC3VECTADDR           (VIC3_BASE + 0x100)
#define rVIC3ADDRESS            (*(volatile unsigned int *)(VIC3_BASE + 0x0F00))
 
//interrupt vector table
 
#define vector_table_base       0xD0037400
 
#define reset_vector            (vector_table_base + 0x00)
#define undef_vector            (vector_table_base + 0x04)
#define sotf_interrupt_vector   (vector_table_base + 0x08)
#define prefetch_vector         (vector_table_base + 0x0C)
#define data_vector             (vector_table_base + 0x10)
#define irq_vector              (vector_table_base + 0x18)
#define fiq_vector              (vector_table_base + 0x1C)
 
#define r_reset_vector                  (*(volatile unsigned int *) reset_vector)
#define r_undef_vector                  (*(volatile unsigned int *) undef_vector)
#define r_sotf_interrupt_vector         (*(volatile unsigned int *) sotf_interrupt_vector)
#define r_prefetch_vector               (*(volatile unsigned int *) prefetch_vector)
#define r_data_vector                   (*(volatile unsigned int *) data_vector)
#define r_irq_vector                    (*(volatile unsigned int *) irq_vector)
#define r_fiq_vector                    (*(volatile unsigned int *) fiq_vector)
 
//interrupt number
 
#define NUM_TIMER0                              (21)
#define NUM_TIMER1                              (22)
#define NUM_TIMER2                              (23)
#define NUM_TIMER3                              (24)
#define NUM_TIMER4                              (25)
#define NUM_SYSTIMER                            (26)
#define NUM_WDT                                 (27)
#define NUM_RTC_ALARM                           (28)
#define NUM_RTC_TICK                            (29)

//rtc interrupt func

//rtc func

static void isr_rtc_alarm()
{
        static int num = 0; 
        printf("rtc interrupt, num = %d...",num++);
        //open rtc alarm interrupt
        rINTP |= (1<<1);

        //clear VIC0ADDR,clear using interrupt process
        rVIC0ADDRESS = 0;
        rVIC1ADDRESS = 0;
        rVIC2ADDRESS = 0;
        rVIC3ADDRESS = 0;
}

static unsigned int num_2_bcd(unsigned int num)
{
        return (((num / 10)<< 4) | (num % 10));
} 

static unsigned int bcd_2_num(unsigned int bcd)
{
        return ((((bcd & (0xf0)) >> 4) *10) + (bcd & (0x0f)) );
}

void set_rtc_time(struct rtc_time  *p)
{
        //set RTCCON,open RTC 
        rRTCCON |= 1;

        //set year month date,hour min,sec,day
        rBCDYEAR = num_2_bcd(p->year - 2000);
        rBCDMON = num_2_bcd(p->month);
        rBCDDATE = num_2_bcd(p->date);
        rBCDHOUR = num_2_bcd(p->hour);
        rBCDMIN = num_2_bcd(p->minute);
        rBCDSEC = num_2_bcd(p->second);
        rBCDDAY = num_2_bcd(p->day);

        //set RTCCON,close RTC 
        rRTCCON &= ~(1);
}

void get_rtc_time(struct rtc_time  *p)
{
        //set RTCCON,open RTC 
        rRTCCON |= 1;

        //get year month date,hour min,sec,day
        p->year = bcd_2_num(rBCDYEAR) + 2000;
        p->month = bcd_2_num(rBCDMON);
        p->date = bcd_2_num(rBCDDATE);
        p->hour = bcd_2_num(rBCDHOUR);
        p->minute = bcd_2_num(rBCDMIN);
        p->second = bcd_2_num(rBCDSEC);
        p->day = bcd_2_num(rBCDDAY);
        //set RTCCON,close RTC 
        rRTCCON &= ~(1);
}

void rtc_alarm()
{
        //set alarm pre 10 trigger
        rALMSEC = num_2_bcd(10);
        //set sec used
        rRTCALM |= 1<<0;
        //set alarm enable
        rRTCALM |= 1<<6;
}


//inner interrupt func
 
static void reset_func()
{
        printf("reset\n");
}
 
static void undef_func()
{
        printf("undef\n");
}
 
static void sotf_interrupt_func()
 
{
        printf("sotf_intrrupt\n");
}
 
static void prefetch_func()
{
        printf("prefetch\n");
}
 
static void data_func()
{
        printf("data\n");
}
 
static void fiq_func()
{
        printf("irq\n");
}
 
void IRQ_handler();
 
static void bind_isr_VICnINTENCLEAR(unsigned long num,void (*handler)())
{
        if(num <32)
        {
                printf("bind ok\n");
                *((volatile unsigned int *)(rVIC0VECTADDR + 4 * (num))) = (unsigned)handler;
        }
        else if(num < 64)
        {
                *((volatile unsigned int *)(rVIC0VECTADDR + 4 * (num-32))) = (unsigned)handler;
        }
        else if(num < 96)
        {
                *((volatile unsigned int *)(rVIC0VECTADDR + 4 * (num-64))) = (unsigned)handler;
        }
        else
        {
                *((volatile unsigned int *)(rVIC0VECTADDR + 4 * (num-96))) = (unsigned)handler;
        }
}
 
static void enable_interrupt(unsigned long num)
{
        unsigned long tmp;
 
        if(num < 32)
        {
                tmp = rVIC0INTENABLE;
                tmp |= (1<<num);
                rVIC0INTENABLE = tmp;
        }
        else if(num < 64)
        {
                tmp = rVIC0INTENABLE;
                tmp |= (1<<(num-32));
                rVIC1INTENABLE = tmp;
        }
        else if(num < 96)
        {
                tmp = rVIC0INTENABLE;
                tmp |= (1<<(num-64));
                rVIC2INTENABLE = tmp;
        }
        else if(num < 200)
        {
                tmp = rVIC0INTENABLE;
                tmp |= (1<<(num-96));
                rVIC3INTENABLE = tmp;
        }
        else
        {
                rVIC0INTENABLE = 0xffffffff;
                rVIC1INTENABLE = 0xffffffff;
                rVIC2INTENABLE = 0xffffffff;
                rVIC3INTENABLE = 0xffffffff;
        }
}
 
void init_inner_interrupt()
{
        //bind interrupt process on interrupt vector table 
        r_reset_vector           =      (unsigned int)reset_func; 
        r_undef_vector           =      (unsigned int)undef_func;
        r_sotf_interrupt_vector  =      (unsigned int)sotf_interrupt_func;
        r_prefetch_vector        =      (unsigned int)prefetch_func;
        r_data_vector            =      (unsigned int)data_func;
        r_irq_vector             =      (unsigned int)IRQ_handler;
        r_fiq_vector             =      (unsigned int)fiq_func;
 
        //select interrupt mode(irq)
        rVIC0INTSELECT = 0x0;
        rVIC1INTSELECT = 0x0;
        rVIC2INTSELECT = 0x0;
        rVIC3INTSELECT = 0x0;
 
        //diasble interrupt
        rVIC0INTENCLEAR = 0xffffffff;
        rVIC1INTENCLEAR = 0xffffffff;
        rVIC2INTENCLEAR = 0xffffffff;
        rVIC3INTENCLEAR = 0xffffffff;
 
        //clear interrupt process address 
        rVIC0ADDRESS = 0;
        rVIC1ADDRESS = 0;
        rVIC2ADDRESS = 0;
        rVIC3ADDRESS = 0;
 
        //bind isr process on VICnINTENCLEAR
        bind_isr_VICnINTENCLEAR(NUM_RTC_ALARM,isr_rtc_alarm);
 
        //enable interrupt
        enable_interrupt(NUM_RTC_ALARM);
}
 
//judge inner interrupt ,get interrupt occure in which VICnVECTADDR
void irq_handler()
{
        volatile unsigned int n = 0;
        void (*isr)(void) = NULL;
        for(n = 0;n <4;n++)
        {
                if(n == 0 && rVIC0IRQSTATUS != 0)
                {
                        isr = (void (*)(void))rVIC0ADDRESS; 
                }
                else if(n == 1 && rVIC1IRQSTATUS != 0)
                {
                        isr = (void (*)(void))rVIC1ADDRESS; 
                }
                else if(n == 2 && rVIC2IRQSTATUS != 0)
                {
                        isr = (void (*)(void))rVIC2ADDRESS; 
                }
                else if(n == 3 && rVIC3IRQSTATUS != 0)
                {
                        isr = (void (*)(void))rVIC3ADDRESS; 
                }
                (*isr)();
        }
}

        link.lds 

SECTIONS
{
        . = 0xd0020010;
 
        .text :
        {
                start.o
                *(.text)
        }
 
        .data :
        {
                *(.data)
        }
 
        .bss :
        {
                *(.bss)
        }
}

        Makefile 

CC      =       arm-linux-gcc
LD      =       arm-linux-ld
OBJCOPY =       arm-linux-objcopy
OBJDUMP =       arm-linux-objdump
 
INCDIR  := $(shell pwd)
 
#预处理器的flag,flag就是编译器可选的选项
CPPFLAGS  := -nostdlib -nostdinc -I$(INCDIR)/include
#C编译器的flag
CFLAGS    := -Wall -O2 -fno-builtin
 
export CC LD OBJCOPY OBJDUMP CPPFLAGS CFLAGS
 
objs      := start.o uart_printf.o main.o rtc_alarm.o
objs      += lib/libc.a
 
led.bin:$(objs)
        $(LD) -Tlink.lds -o rtc_alarm.elf $^
        $(OBJCOPY) -O binary rtc_alarm.elf rtc_alarm.bin
        $(OBJDUMP) -D rtc_alarm.elf > rtc_alarm.dis
        gcc mkv210.c -o mkv210
        ./mkv210 rtc_alarm.bin sd.bin
 
lib/libc.a:
        cd lib;  make;  cd ..
 
%.o:%.S
        $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $< -c
 
%.o:%.c
        $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $< -c
 
clean:
        rm *.o *.elf *.bin *.dis mkv210 -f
        cd lib; make clean; cd ..

结果示例: 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/tyro_wzp/article/details/133947675

智能推荐

c# 调用c++ lib静态库_c#调用lib-程序员宅基地

文章浏览阅读2w次,点赞7次,收藏51次。四个步骤1.创建C++ Win32项目动态库dll 2.在Win32项目动态库中添加 外部依赖项 lib头文件和lib库3.导出C接口4.c#调用c++动态库开始你的表演...①创建一个空白的解决方案,在解决方案中添加 Visual C++ , Win32 项目空白解决方案的创建:添加Visual C++ , Win32 项目这......_c#调用lib

deepin/ubuntu安装苹方字体-程序员宅基地

文章浏览阅读4.6k次。苹方字体是苹果系统上的黑体,挺好看的。注重颜值的网站都会使用,例如知乎:font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, PingFang SC, Microsoft YaHei, Source Han Sans SC, Noto Sans CJK SC, W..._ubuntu pingfang

html表单常见操作汇总_html表单的处理程序有那些-程序员宅基地

文章浏览阅读159次。表单表单概述表单标签表单域按钮控件demo表单标签表单标签基本语法结构<form action="处理数据程序的url地址“ method=”get|post“ name="表单名称”></form><!--action,当提交表单时,向何处发送表单中的数据,地址可以是相对地址也可以是绝对地址--><!--method将表单中的数据传送给服务器处理,get方式直接显示在url地址中,数据可以被缓存,且长度有限制;而post方式数据隐藏传输,_html表单的处理程序有那些

PHP设置谷歌验证器(Google Authenticator)实现操作二步验证_php otp 验证器-程序员宅基地

文章浏览阅读1.2k次。使用说明:开启Google的登陆二步验证(即Google Authenticator服务)后用户登陆时需要输入额外由手机客户端生成的一次性密码。实现Google Authenticator功能需要服务器端和客户端的支持。服务器端负责密钥的生成、验证一次性密码是否正确。客户端记录密钥后生成一次性密码。下载谷歌验证类库文件放到项目合适位置(我这边放在项目Vender下面)https://github.com/PHPGangsta/GoogleAuthenticatorPHP代码示例://引入谷_php otp 验证器

【Python】matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距-程序员宅基地

文章浏览阅读4.3k次,点赞5次,收藏11次。matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距

docker — 容器存储_docker 保存容器-程序员宅基地

文章浏览阅读2.2k次。①Storage driver 处理各镜像层及容器层的处理细节,实现了多层数据的堆叠,为用户 提供了多层数据合并后的统一视图②所有 Storage driver 都使用可堆叠图像层和写时复制(CoW)策略③docker info 命令可查看当系统上的 storage driver主要用于测试目的,不建议用于生成环境。_docker 保存容器

随便推点

网络拓扑结构_网络拓扑csdn-程序员宅基地

文章浏览阅读834次,点赞27次,收藏13次。网络拓扑结构是指计算机网络中各组件(如计算机、服务器、打印机、路由器、交换机等设备)及其连接线路在物理布局或逻辑构型上的排列形式。这种布局不仅描述了设备间的实际物理连接方式,也决定了数据在网络中流动的路径和方式。不同的网络拓扑结构影响着网络的性能、可靠性、可扩展性及管理维护的难易程度。_网络拓扑csdn

JS重写Date函数,兼容IOS系统_date.prototype 将所有 ios-程序员宅基地

文章浏览阅读1.8k次,点赞5次,收藏8次。IOS系统Date的坑要创建一个指定时间的new Date对象时,通常的做法是:new Date("2020-09-21 11:11:00")这行代码在 PC 端和安卓端都是正常的,而在 iOS 端则会提示 Invalid Date 无效日期。在IOS年月日中间的横岗许换成斜杠,也就是new Date("2020/09/21 11:11:00")通常为了兼容IOS的这个坑,需要做一些额外的特殊处理,笔者在开发的时候经常会忘了兼容IOS系统。所以就想试着重写Date函数,一劳永逸,避免每次ne_date.prototype 将所有 ios

如何将EXCEL表导入plsql数据库中-程序员宅基地

文章浏览阅读5.3k次。方法一:用PLSQL Developer工具。 1 在PLSQL Developer的sql window里输入select * from test for update; 2 按F8执行 3 打开锁, 再按一下加号. 鼠标点到第一列的列头,使全列成选中状态,然后粘贴,最后commit提交即可。(前提..._excel导入pl/sql

Git常用命令速查手册-程序员宅基地

文章浏览阅读83次。Git常用命令速查手册1、初始化仓库git init2、将文件添加到仓库git add 文件名 # 将工作区的某个文件添加到暂存区 git add -u # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,不处理untracked的文件git add -A # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,包括untracked的文件...

分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120-程序员宅基地

文章浏览阅读202次。分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120

【C++缺省函数】 空类默认产生的6个类成员函数_空类默认产生哪些类成员函数-程序员宅基地

文章浏览阅读1.8k次。版权声明:转载请注明出处 http://blog.csdn.net/irean_lau。目录(?)[+]1、缺省构造函数。2、缺省拷贝构造函数。3、 缺省析构函数。4、缺省赋值运算符。5、缺省取址运算符。6、 缺省取址运算符 const。[cpp] view plain copy_空类默认产生哪些类成员函数

推荐文章

热门文章

相关标签