(ARM11 S3C6410)关于裸机串口与定时器
调试MCU经常需要用串口。
裸机前后台系统,基本就是基于定时器中断。
init.s 启动代码
Mode_USR EQU 0x10 Mode_FIQ EQU 0x11 Mode_IRQ EQU 0x12 Mode_SVC EQU 0x13 Mode_ABT EQU 0x17 Mode_UND EQU 0x1B Mode_SYS EQU 0x1F UND_Stack_Size EQU 0x00000400 SVC_Stack_Size EQU 0x00001000 ABT_Stack_Size EQU 0x00000400 FIQ_Stack_Size EQU 0x00000400 IRQ_Stack_Size EQU 0x00001000 USR_Stack_Size EQU 0x00001000 Heap_Size EQU 0x00010000 I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled Stack_Top EQU 0x52000000 IMPORT main PRESERVE8 AREA |VIC|,CODE,READONLY ENTRY start mrc p15,0,r0,c1,c0,0 orr r0,r0,#(1<<24) mcr p15,0,r0,c1,c0,0 LDR R0, =Stack_Top MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit MOV SP, R0 SUB R0, R0, #UND_Stack_Size MSR CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit MOV SP, R0 SUB R0, R0, #ABT_Stack_Size MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit MOV SP, R0 SUB R0, R0, #FIQ_Stack_Size MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit MOV SP, R0 SUB R0, R0, #IRQ_Stack_Size MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit MOV SP, R0 SUB SL, SP, #USR_Stack_Size MSR CPSR_c, #Mode_USR MOV SP, R0 SUB SL, SP, #USR_Stack_Size ;使能IQR中断 MRS R0,CPSR BIC R0,R0,#0x80 MSR CPSR_c,R0 bl main END
6410_include.h 一些重定义类型 与宏定义。
#ifndef __DEF_H__ #define __DEF_H__ #define FIN 12000000 //晶振频率 // 读/写寄存器数据 #define Outp32(addr, data) (*(volatile u32 *)(addr) = (data)) #define Outp16(addr, data) (*(volatile u16 *)(addr) = (data)) #define Outp8(addr, data) (*(volatile u8 *)(addr) = (data)) #define Inp32(addr) (*(volatile u32 *)(addr)) #define Inp16(addr) (*(volatile u16 *)(addr)) #define Inp8(addr) (*(volatile u8 *)(addr)) typedef unsigned long u32; typedef unsigned short u16; typedef unsigned char u8; typedef signed long s32; typedef signed short s16; typedef signed char s8; #endif
uart.h 串口驱动头文件
#include "6410_include.h" #ifndef __UART_H__ #define __UART_H__ #define ULCON0 (0x7F005000) #define UCON0 (0x7F005004) #define UFCON0 (0x7F005008) #define UMCON0 (0x7F00500C) #define UBRDIV0 (0x7F005028) #define GPACON (0X7F008000) #define GPAPUD (0X7F008008) #define UTRSTAT0 (*(volatile unsigned *)(0x7F005010)) #define UTXH0 (*(volatile unsigned *)(0x7F005020)) #define UART_clock 66500000 #endif void Uart0_Init(u32 baud); void Uart_Putc(char ch); void Uart_Puts(char *str); void Uart_Printf(char *fmt,...);
uart.c 串口驱动
#include "6410_include.h" #include <stdarg.h> #include "uart.h" //端口初始化; static void Uart0_Port_Init(void) { u32 uConValue; uConValue = Inp32(GPACON); uConValue = (uConValue & ~0xff) | 0x22; //配置为UART0功能; Outp32(GPACON,uConValue); uConValue = Inp32(GPAPUD); uConValue &= ~0xf; //低4位配置为0000,上下拉电阻除能; Outp32(GPAPUD,uConValue); } //uart初始化; void Uart0_Init(u32 baud) { u32 pclk; u32 uConValue; u32 uTemp; pclk = UART_clock; Uart0_Port_Init(); uConValue = Inp32(ULCON0); uConValue = (uConValue & ~0x3F) | 0x3;//配置为8位数据,1位停止位,0位校验位; Outp32(ULCON0,uConValue); uConValue = Inp32(UCON0); uConValue= (uConValue & ~0x405| 0x405); //配置为中断或轮询模式,使用pclk作为波特率; Outp32(UCON0,uConValue); uConValue = Inp32(UFCON0); uConValue = 0x0;//配置为非FIFO模式; Outp32(UFCON0,uConValue); uConValue = Inp32(UMCON0); uConValue = 0x0;//配置为非中断,非流控模式; Outp32(UMCON0,uConValue); uTemp = (int)(pclk/16/baud)- 1; Outp32(UBRDIV0,uTemp);//配置波特率; Delay(10000); } //单字符输出; void Uart_Putc(char ch) { if(ch == '\n') { while(!(UTRSTAT0 & 0x2)); UTXH0 = '\r'; } while(!(UTRSTAT0 & 0x2)); UTXH0 = ch; } //字符串输出 void Uart_Puts(char *str) { while(*str) { Uart_Putc(*str++); } } //格式化输出; void Uart_Printf(char *fmt,...) { char str[256]; va_list ap; va_start(ap,fmt); //va_start() 与 va_end() 需要对称 vsprintf(str,fmt,ap); Uart_Puts(str); va_end(ap); }
timer0.h 定时器0头文件
#include "6410_include.h" #ifndef __TIMER_H__ #define __TIMER_H__ #define TINT_CSTAT (*(volatile unsigned*)(0x7F006044)) #define TCFG0 (*(volatile unsigned*)(0x7F006000)) #define TCFG1 (*(volatile unsigned*)(0x7F006004)) #define TCON (*(volatile unsigned*)(0x7F006008)) #define TCNTB0 (*(volatile unsigned*)(0x7F00600C)) #define TCMPB0 (*(volatile unsigned*)(0x7F006010)) #define TCNTO0 (*(volatile unsigned*)(0x7F006014)) #define TCNTB1 (*(volatile unsigned*)(0x7F006018)) #define TCMPB1 (*(volatile unsigned*)(0x7F00601c)) #define TCNTO1 (*(volatile unsigned*)(0x7F006020)) #define TCNTB2 (*(volatile unsigned*)(0x7F006024)) #define TCNTO2 (*(volatile unsigned*)(0x7F00602c)) #define TCNTB3 (*(volatile unsigned*)(0x7F006030)) #define TCNTO3 (*(volatile unsigned*)(0x7F006038)) #define TCNTB4 (*(volatile unsigned*)(0x7F00603c)) #define TCNTO4 (*(volatile unsigned*)(0x7F006040)) #define VIC0ADDRESS (*(volatile unsigned *)(0x71200f00)) #define VIC0INTENABLE (*(volatile unsigned *)(0x71200010)) #define VIC0VECTADDR0 0x71200100 #define NUM_TIMER0 23 #endif //__TIMER_H__ void __irq Isr_TIMER0(void); void Timer0_Init(u32 Time0_Value);
timer0.c 定时器驱动代码
#include "timer0.h" #include "uart.h" #include "LED.h" u8 led_sw = 1; //中断服务函数 void __irq Isr_Timer(void) { led_sw = !led_sw; LED1(led_sw); Uart_Printf("timer_ISR\n"); TINT_CSTAT |= (1<<5); //清time0中断标志 VIC0ADDRESS = 0; //貌似VIC0ADDRESS中存放着当前中断的入口地址,清除地址。 } //定时器初始化; void Timer0_Init(u32 Time0_Value) { TCFG0 &= 0xffffff00; TCFG0 |= 0x00000041; //设置预分频器为65 TCFG1 &= ~1; //设置定时器0的MUX为1/1 TCNTB0 = Time0_Value; //timer0计数器值 TINT_CSTAT |= 0x01; //timer0中断使能 VIC0INTENABLE |= (1<<23); //timer0中断使能 TCON |= 0x0B; //开始timer0,更新CNTB0,TCMPB0,自动重装模式 TCON &= ~0x02; //启动定时器后要关闭手动更新位 (*(volatile unsigned *)(VIC0VECTADDR0+4*NUM_TIMER0)) = (u32)Isr_Timer; //注册安装定时器的中断函数: 每个寄存器存有4个字节的地址所以乘以4 }
main 主函数
#include "LED.h" #include "uart.h" #include "time0.h" int main(void) { Uart0_Init(115200); LED_init(); Timer0_Init(300000); while(1); }