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

智能推荐

什么是内部类?成员内部类、静态内部类、局部内部类和匿名内部类的区别及作用?_成员内部类和局部内部类的区别-程序员宅基地

文章浏览阅读3.4k次,点赞8次,收藏42次。一、什么是内部类?or 内部类的概念内部类是定义在另一个类中的类;下面类TestB是类TestA的内部类。即内部类对象引用了实例化该内部对象的外围类对象。public class TestA{ class TestB {}}二、 为什么需要内部类?or 内部类有什么作用?1、 内部类方法可以访问该类定义所在的作用域中的数据,包括私有数据。2、内部类可以对同一个包中的其他类隐藏起来。3、 当想要定义一个回调函数且不想编写大量代码时,使用匿名内部类比较便捷。三、 内部类的分类成员内部_成员内部类和局部内部类的区别

分布式系统_分布式系统运维工具-程序员宅基地

文章浏览阅读118次。分布式系统要求拆分分布式思想的实质搭配要求分布式系统要求按照某些特定的规则将项目进行拆分。如果将一个项目的所有模板功能都写到一起,当某个模块出现问题时将直接导致整个服务器出现问题。拆分按照业务拆分为不同的服务器,有效的降低系统架构的耦合性在业务拆分的基础上可按照代码层级进行拆分(view、controller、service、pojo)分布式思想的实质分布式思想的实质是为了系统的..._分布式系统运维工具

用Exce分析l数据极简入门_exce l趋势分析数据量-程序员宅基地

文章浏览阅读174次。1.数据源准备2.数据处理step1:数据表处理应用函数:①VLOOKUP函数; ② CONCATENATE函数终表:step2:数据透视表统计分析(1) 透视表汇总不同渠道用户数, 金额(2)透视表汇总不同日期购买用户数,金额(3)透视表汇总不同用户购买订单数,金额step3:讲第二步结果可视化, 比如, 柱形图(1)不同渠道用户数, 金额(2)不同日期..._exce l趋势分析数据量

宁盾堡垒机双因素认证方案_horizon宁盾双因素配置-程序员宅基地

文章浏览阅读3.3k次。堡垒机可以为企业实现服务器、网络设备、数据库、安全设备等的集中管控和安全可靠运行,帮助IT运维人员提高工作效率。通俗来说,就是用来控制哪些人可以登录哪些资产(事先防范和事中控制),以及录像记录登录资产后做了什么事情(事后溯源)。由于堡垒机内部保存着企业所有的设备资产和权限关系,是企业内部信息安全的重要一环。但目前出现的以下问题产生了很大安全隐患:密码设置过于简单,容易被暴力破解;为方便记忆,设置统一的密码,一旦单点被破,极易引发全面危机。在单一的静态密码验证机制下,登录密码是堡垒机安全的唯一_horizon宁盾双因素配置

谷歌浏览器安装(Win、Linux、离线安装)_chrome linux debian离线安装依赖-程序员宅基地

文章浏览阅读7.7k次,点赞4次,收藏16次。Chrome作为一款挺不错的浏览器,其有着诸多的优良特性,并且支持跨平台。其支持(Windows、Linux、Mac OS X、BSD、Android),在绝大多数情况下,其的安装都很简单,但有时会由于网络原因,无法安装,所以在这里总结下Chrome的安装。Windows下的安装:在线安装:离线安装:Linux下的安装:在线安装:离线安装:..._chrome linux debian离线安装依赖

烤仔TVの尚书房 | 逃离北上广?不如押宝越南“北上广”-程序员宅基地

文章浏览阅读153次。中国发达城市榜单每天都在刷新,但无非是北上广轮流坐庄。北京拥有最顶尖的文化资源,上海是“摩登”的国际化大都市,广州是活力四射的千年商都。GDP和发展潜力是衡量城市的数字指...

随便推点

java spark的使用和配置_使用java调用spark注册进去的程序-程序员宅基地

文章浏览阅读3.3k次。前言spark在java使用比较少,多是scala的用法,我这里介绍一下我在项目中使用的代码配置详细算法的使用请点击我主页列表查看版本jar版本说明spark3.0.1scala2.12这个版本注意和spark版本对应,只是为了引jar包springboot版本2.3.2.RELEASEmaven<!-- spark --> <dependency> <gro_使用java调用spark注册进去的程序

汽车零部件开发工具巨头V公司全套bootloader中UDS协议栈源代码,自己完成底层外设驱动开发后,集成即可使用_uds协议栈 源代码-程序员宅基地

文章浏览阅读4.8k次。汽车零部件开发工具巨头V公司全套bootloader中UDS协议栈源代码,自己完成底层外设驱动开发后,集成即可使用,代码精简高效,大厂出品有量产保证。:139800617636213023darcy169_uds协议栈 源代码

AUTOSAR基础篇之OS(下)_autosar 定义了 5 种多核支持类型-程序员宅基地

文章浏览阅读4.6k次,点赞20次,收藏148次。AUTOSAR基础篇之OS(下)前言首先,请问大家几个小小的问题,你清楚:你知道多核OS在什么场景下使用吗?多核系统OS又是如何协同启动或者关闭的呢?AUTOSAR OS存在哪些功能安全等方面的要求呢?多核OS之间的启动关闭与单核相比又存在哪些异同呢?。。。。。。今天,我们来一起探索并回答这些问题。为了便于大家理解,以下是本文的主题大纲:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JCXrdI0k-1636287756923)(https://gite_autosar 定义了 5 种多核支持类型

VS报错无法打开自己写的头文件_vs2013打不开自己定义的头文件-程序员宅基地

文章浏览阅读2.2k次,点赞6次,收藏14次。原因:自己写的头文件没有被加入到方案的包含目录中去,无法被检索到,也就无法打开。将自己写的头文件都放入header files。然后在VS界面上,右键方案名,点击属性。将自己头文件夹的目录添加进去。_vs2013打不开自己定义的头文件

【Redis】Redis基础命令集详解_redis命令-程序员宅基地

文章浏览阅读3.3w次,点赞80次,收藏342次。此时,可以将系统中所有用户的 Session 数据全部保存到 Redis 中,用户在提交新的请求后,系统先从Redis 中查找相应的Session 数据,如果存在,则再进行相关操作,否则跳转到登录页面。此时,可以将系统中所有用户的 Session 数据全部保存到 Redis 中,用户在提交新的请求后,系统先从Redis 中查找相应的Session 数据,如果存在,则再进行相关操作,否则跳转到登录页面。当数据量很大时,count 的数量的指定可能会不起作用,Redis 会自动调整每次的遍历数目。_redis命令

URP渲染管线简介-程序员宅基地

文章浏览阅读449次,点赞3次,收藏3次。URP的设计目标是在保持高性能的同时,提供更多的渲染功能和自定义选项。与普通项目相比,会多出Presets文件夹,里面包含着一些设置,包括本色,声音,法线,贴图等设置。全局只有主光源和附加光源,主光源只支持平行光,附加光源数量有限制,主光源和附加光源在一次Pass中可以一起着色。URP:全局只有主光源和附加光源,主光源只支持平行光,附加光源数量有限制,一次Pass可以计算多个光源。可编程渲染管线:渲染策略是可以供程序员定制的,可以定制的有:光照计算和光源,深度测试,摄像机光照烘焙,后期处理策略等等。_urp渲染管线

推荐文章

热门文章

相关标签