S3C2440电阻触摸屏驱动设计

最后更新于:2022-04-01 16:11:51

实验:当触笔点击在触摸屏上时,SecureCRT上显示触点的X,Y坐标; 目的:测试电阻触摸屏驱动程序; 开发板:S3C2440 ~~~ /* *版权所有(C)2015,ZJU * *文件名称:ts.c *内容摘要:关于触摸屏的配置 *其它说明:开发板型号: TX2440 * 电阻屏 *当前版本:V1.0 *作 者:Frank *完成日期:2015.12.22 * */ #define ADCCON (*(volatile unsigned int *)0x58000000) //ADC control register #define ADCTSC (*(volatile unsigned int *)0x58000004) //ADC Touch Screen Control Register #define ADCDLY (*(volatile unsigned int *)0x58000008) //ADC Start or interval delay register #define ADCDATA0 (*(volatile unsigned int *)0x5800000C) //ADC conversion data register #define ADCDATA1 (*(volatile unsigned int *)0x58000010) //ADC conversion data register /*interrupt register*/ #define SRCPND (*(volatile unsigned long *)0x4A000000) #define INTMSK (*(volatile unsigned long *)0x4A000008) #define INTPND (*(volatile unsigned long *)0x4A000010) #define INTOFFSET (*(volatile unsigned long *)0x4A000014) #define SUBSRCPND (*(volatile unsigned long *)0x4A000018) #define INTSUBMSK (*(volatile unsigned long *)0x4A00001C) int xdata=0; int ydata=0; /******************************************************************* *函数名称:Ts_Init() *功能描述:触摸屏工作初始化 *其他说明:配置ADC为触摸屏工作模式 *创建日期:2015.12.22 *******************************************************************/ void Ts_Init(void) { /*1、设置AD转换时钟*/ ADCCON = (1 << 14) | (49 << 6); //AD转换频率=PCLK/(Val + 1),此处设为 1MHz /*2、设置中断屏蔽位*/ INTMSK = ~(1 << 31); INTSUBMSK = ~(1 << 9); /*3、进入等待中断的模式*/ ADCTSC = 0xd3; /***清除CPSR寄存器中的第7位I(IRQ disable),因为在start.S中关闭了中断****/ //这一步的目的是开启总中断 __asm__( "mrs r0, cpsr\n" "bic r0, r0, #0x80\n" "msr cpsr_c, r0\n" : : ); } /******************************************************************* *函数名称:Ts_Handler() *功能描述:触摸屏中断处理 *其他说明:按下触摸屏后的中断处理 *创建日期:2015.12.22 *******************************************************************/ void Ts_Handler(void) { /*1、启动XY坐标自动转换*/ ADCTSC = (1 << 2); ADCCON |= (1 << 0); /*2、等待转换完成*/ while(!(ADCCON & (1 << 15))); /*3、获取坐标*/ xdata = ADCDATA0 & 0x3ff; ydata = ADCDATA1 & 0x3ff; /*4、清除按下中断*/ SUBSRCPND |= (1 << 9); SRCPND = (1 << 31); INTPND = (1 << 31); /*5、进入等待弹起中断*/ ADCTSC = 0xd3; ADCTSC |= (1 << 8); while(1) { if (SUBSRCPND & (1 << 9)) break; } /*6、清除弹起中断*/ SUBSRCPND |= (1 << 9); SRCPND = (1 << 31); INTPND = (1 << 31); //对读取到的X,Y坐标进行处理 printf("X is %d, Y is %d\n", xdata, ydata); printf("\n\r"); /*7、再次进入等待按下中断的状态*/ ADCTSC = 0xd3; } ~~~ 中断处理文件interrupt.c中触摸屏中断函数的调用程序: ~~~ /******************************************************************* *函数名称:handle_int() *功能描述:中断处理函数 *其他说明: *******************************************************************/ void handle_int() { /*判断产生中断的中断源*/ unsigned long value = *(INTOFFSET); switch (value) { case 31 : Ts_Handler(); //触摸屏中断 break; default : break; } } ~~~
';

linux中宿主目录、Vi和Vim关系

最后更新于:2022-04-01 16:11:48

1、宿主目录:所谓宿主目录,就是操作系统为当前用户所设计的用来存放文件、工作的默认目录。如windows中的“我的文档”,就是windows为我们设计的宿主目录。       linux中每个用户都有自己的宿主目录,这个目录对于普通用户来说,在home/username,而对于root用户来说,在/root。所以当用户为root时,~与/root等价。 2、为什么在linux中键入vi等价于键入vim?       vim是vi的升级版。其实现在使用vi不是真正的打开vi编辑器,现在的vi其实是一个link文件,指向的是vim,所以键入vi相当于键入vim。 3、vi的高级使用      ①查找:在命令模式下,输入 /xxx,就可以查找到xxx;      ②快速切换行:在命令模式下,输入:num,就可以快速切换到num行;      ③设置显示行号:在命令模式下,输入:set  nu,就可以显示行号;      ④取消显示行号:在命令模式下,输入:set  nonu,就可以取消显示行号。
';

S3C2440 LCD液晶模块驱动设计

最后更新于:2022-04-01 16:11:46

参数配置: 开发板型号TX2440;  一个像素点采用16位表示; LCD屏幕分辨率 480*272; 液晶模块型号:BL43014_SPEC;图像的内容以C语言数组的形式保存在bmp.c文件中。 ~~~ /* *版权所有(C)2015,ZJU * *文件名称:lcd.c *内容摘要:关于lcd的配置 *其它说明:开发板型号: TX2440 * led显示尺寸 480 x 272 液晶模块型号:BL43014_SPEC *当前版本:V1.0 *作 者:Frank *完成日期:2015.12.20 * */ #define GPCCON (*(volatile unsigned long *)0x56000020) #define GPDCON (*(volatile unsigned long *)0x56000030) #define GPGCON (*(volatile unsigned long *)0x56000060) //LCD控制寄存器定义 #define LCDCON1 (*(volatile unsigned long *)0x4D000000) #define LCDCON2 (*(volatile unsigned long *)0x4D000004) #define LCDCON3 (*(volatile unsigned long *)0x4D000008) #define LCDCON4 (*(volatile unsigned long *)0x4D00000C) #define LCDCON5 (*(volatile unsigned long *)0x4D000010) #define LCDSADDR1 (*(volatile unsigned long *)0x4D000014) #define LCDSADDR2 (*(volatile unsigned long *)0x4D000018) #define LCDSADDR3 (*(volatile unsigned long *)0x4D00001C) #define TPAL (*(volatile unsigned long *)0x4D000050) /*以下宏定义的值参考所使用的LCD液晶模块的芯片手册*/ #define VSPW 9 #define VBPD 7 #define LINEVAL 271 #define VFPD 7 #define CLKVAL 4 // 10 = 100 / ((CLKVAL+1)*2) #define HSPW 40 #define HBPD 39 #define HOZVAL 479 #define HFPD 4 unsigned short LCDBUFFER[272][480]; //定义一个LCD图像缓存空间 extern unsigned char bmp[90200]; typedef unsigned char U8; typedef unsigned short int U16; typedef unsigned int U32; /******************************************************************* *函数名称:Lcd_Port_Init() *功能描述:LCD端口初始化 *其他说明:配置LCD用到的GPIO端口 *创建日期:2015.12.20 *******************************************************************/ void Lcd_Port_Init(void) { GPDCON = 0xaaaaaaaa; GPCCON = 0xaaaaaaaa; } /******************************************************************* *函数名称:Lcd_Control_Init() *功能描述:LCD控制寄存器初始化 *其他说明:配置LCD用到的控制寄存器 *创建日期:2015.12.20 *******************************************************************/ void Lcd_Control_Init(void) { LCDCON1 = (CLKVAL << 8) | (0x3 << 5) | (0xC << 1) | (0 << 0); LCDCON2 = (VBPD << 24) | (LINEVAL << 14) | (VFPD << 6) | (VSPW); LCDCON3 = (HBPD << 19) | (HOZVAL << 8) | (HFPD); LCDCON4 = HSPW; // LCDCON5 = (1 << 11) | (1 << 9) | (1 << 8) | (1 << 0); LCDCON5 = (1 << 11) | (1 << 9) | (1 << 8); LCDSADDR1 = (((unsigned int)LCDBUFFER >> 22) << 21) | (((unsigned int)LCDBUFFER >> 1) & 0x1fffff); LCDSADDR2 = (((unsigned int)LCDBUFFER + 272*480*2) >> 1) & 0x1fffff; LCDSADDR3 = (0 << 11) | (480*2 / 2); TPAL = 0; } /******************************************************************* *函数名称:Lcd_Init() *功能描述:LCD初始化 *其他说明: *创建日期:2015.12.20 *******************************************************************/ void Lcd_Init() { Lcd_Port_Init(); Lcd_Control_Init(); /*打开LCD电源*/ GPGCON |= (0x3 << 8); LCDCON5 |= (1 << 3); /*使能LCD控制器*/ LCDCON1 |= 1; } /******************************************************************* *函数名称:point() *功能描述:在lcd上画一个点 *其他说明: *创建日期:2015.12.20 *******************************************************************/ void Point(unsigned int x, unsigned int y, unsigned int color) { unsigned int red, green, blue; red = (color >> 19) & 0x1f; green = (color >> 10) & 0x3f; blue = (color >> 3) & 0x1f; /*采用5:6:5的模式表示一个RGB*/ LCDBUFFER[y][x] = (unsigned short)((red << 11) | (green << 5) | blue); } /******************************************************************* *函数名称:Paint_Bmp(U16,U16,U16,U16,U8) *功能描述:LCD显示一幅图像 *输入参数:(x0,y0)图像显示第一个点的坐标; high图像的高度 wide图像的宽度; bmp存储图像的数组 *其他说明: *创建日期:2015.12.20 *******************************************************************/ void Paint_Bmp(U16 x0, U16 y0, U16 wide, U16 high, const U8 *bmp) { unsigned short x, y; unsigned short c; unsigned int p = 0; for (y=y0; y<y0+high; y++) { for (x=x0; x<x0+wide; x++) { c = bmp[p] | (bmp[p+1]<<8); /*一个像素点由16位表示,bmp[p] 表示低8位,bmp[p+1]表示高8位*/ if ((x<480) && (y<272)) { LCDBUFFER[y][x] = c; } p = p + 2; } } } /******************************************************************* *函数名称:Lcd_Test() *功能描述:LCD测试函数 *其他说明: *创建日期:2015.12.20 *******************************************************************/ void Lcd_Test(void) { int x; /* for (x=0; x<480; ++x) { Point(x++, 150, 0xff0000); } */ Paint_Bmp(0,0,220,220,bmp); } ~~~ 需要注意的几点: 1、宏定义的值需要参考使用的LCD液晶模块的芯片手册(TX2440使用的LCD是BL43014_SPEC) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-26_579724f9a7b54.jpg) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-26_579724f9c733d.jpg) 图1 BL43014_SPEC Input Time Table 2、液晶模块的Vsync和Hsync的时序与S3C2440芯片手册上的相反,所以LCDCON5中bit8和bit9需要设置为1。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-26_579724f9e6495.jpg) 图2 BL43014_SPEC Vertical Input Timing ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-26_579724fa0cc5e.jpg) 图3 TFT LCD Timing Example( S3C2440 Datasheet)
';

S3C2440 – DMA传输(以字符传输为例)

最后更新于:2022-04-01 16:11:44

## 一、使用DMA的优点及DMA支持的请求源 1、DMA优点是其进行数据传输时不需要CPU的干涉,可以大大提高CPU的工作效率。 2、DMA在大容量数据传输中非常重要,比如图像数据传输,SD卡数据传输,USB数据传输等。 3、S3C2440有四个DMA,每个DMA支持的工作方式基本相同,但支持的DMA请求源可能略有不同。如下为四个DMA通道分别支持的DMA请求源: Ch0:    nXDREQ0,      UART0,      SDI,            Timer,         USB EP1 Ch1:    nXDREQ1,      UART1,      I2SSDI,       SPI0,          USB EP2 Ch2:    I2SSDO,          I2SSDI,      SDI,            Timer,         USB EP3 Ch3:    UART1,           SDI,            SPI1,          Timer,         USB EP4 那么怎么使用DMA呢,S3C2440内部集成了DMA控制器,我们只需要简单的配置一下寄存器就可以实现DMA的传输了。 ## 二、DMA配置步骤及要点: (参考[点击打开链接](http://blog.csdn.net/cybertan/article/details/4697516)) 1.数据从哪里来,到哪里去? 使用DMA首先我们要知道数据的流向,DISRCx寄存器是DMA初始源寄存器,存放了数据的源地址。DIDSTx是DMA的初始目的寄存器,存放数据的目的地址。 2.数据走的什么总线?地址是否是固定的? 我们还要知道源与目的数据存储设备在什么总线上(AHB系统总线,一般是高速的比如内存,APB外围总线,低速的比如SD,UART;具体走什么总线可以在datasheet上查到);以及数据传输结束以后起始地址还原到发送前的起始地址呢,还是在现在的末尾+1做为新的起始地址。这些设置在DISRCCx与DIDSTCx两个寄存器里面配置。 3.数据以什么方式传输?源与目的是什么设备?要不要自动重载? 需要确定数据的传输方式有请求还是握手,根据上面的总线确定与什么时钟同步(HCLK,PCLK),是单元传输还是突发传输,是以字节传输还是字传输,是否重载。是单服务(只发送一次)还是多服务(不停循环发送),以及数据的传送大小。选择源与目的设备。最后还要确定中断是不是传输结束发生(CURR_TC记数是不是0)。这些都在DCONx中设置。 4.怎么开始传输DMA和停止DMA,这些在DMASKTRIG中设置。 ## 三、操作实例(以DMA传输一段字符到控制台为例) ~~~ /* *版权所有(C)2015,ZJU * *文件名称:dma.c *内容摘要:关于DMA的配置 *其它说明:开发板型号: TX2440 * 注意Uart_Init中,设置UCON0寄存器时TX的方式要设置为DMA模式 *当前版本:V1.0 *作 者:Frank *完成日期:2015.12.19 * */ #define DISRC0 (*(volatile unsigned long *)0x4B000000) //DMA 0 initial source register #define DISRCC0 (*(volatile unsigned long *)0x4B000004) //DMA 0 initial source control register #define DIDST0 (*(volatile unsigned long *)0x4B000008) //DMA 0 initial destination register #define DIDSTC0 (*(volatile unsigned long *)0x4B00000C) //DMA 0 initial destination control register #define DCON0 (*(volatile unsigned long *)0x4B000010) //DMA 0 control register #define DMASKTRIG0 (*(volatile unsigned long *)0x4B000020) //DMA 0 mask trigger register #define UTXH0 (volatile unsigned long *)0x50000020 //UART channel 0 transmit buffer register char *buf = "Hello World!"; /******************************************************************* *函数名称:Dma_Init() *功能描述:DMA初始化函数 *其他说明: *创建日期:2015.12.19 *******************************************************************/ void Dma_Init(void) { //初始化源地址 DISRC0 = (unsigned int)buf; DISRCC0 = (0 << 1) | (0 << 0); //DMA起始地址在AHB总线(Memory), 地址递增 //初始化目的地址 DIDST0 = (unsigned int)UTXH0; //目的地址为 UTXH0 DIDSTC0 = (1 << 1) | (1 << 0); /*DMA目的地址在APB总线(UART0), 地址不 变(因为要发送的字符总是传到UTXH0)*/ DCON0 = (1 << 24) | (1 << 23) | (1 << 22) | (12 << 0); //设置DMA请求源及工作模式 } /******************************************************************* *函数名称:Dma_Start() *功能描述:DMA启动函数 *其他说明: *创建日期:2015.12.19 *******************************************************************/ void Dma_Start(void) { DMASKTRIG0 = (1 << 1); //启动DMA通道 } ~~~ 需要注意的几点是: ①没有使用DMA中断; ②使用的是Demand模式,实测发现Handshake模式也是可以的(推荐); ③在Uart_Init中,要将UCON0寄存器设置为发送采用DMA模式(开始就是没有设置,所以一直无法看到实验现象); ④源地址和目的地址要使用unsigned int强制转换为整数放进寄存器中;
';

UART裸机驱动设计

最后更新于:2022-04-01 16:11:42

UART裸机驱动设计主要在于配置各寄存器的值; 开发板型号: TX2440; UART 使能: 使能UART0; 传 输 参 数: 8位数据位,1位停止位,无奇偶校验,波特率115200; 时 钟 参 数: UART使用系统的 PCLK. ~~~ /******************************************************************* *版权所有(C)2015,ZJU * *文件名称:uart.c *内容摘要:关于UART的配置 *其它说明:开发板型号:TX2440 * UART0:RXD0 -- GPH3 , TXD0 -- GPH2 *当前版本:V1.0 *作 者:Frank *完成日期:2015.12.14 * *******************************************************************/ #define GPHCON (*(volatile unsigned long *)0x56000070) //Configures the pins of port H #define ULCON0 (*(volatile unsigned long *)0x50000000) //UART channel 0 line control register #define UCON0 (*(volatile unsigned long *)0x50000004) //UART channel 0 control register #define UTRSTAT0 (*(volatile unsigned long *)0x50000010) //UART channel 0 Tx/Rx status register #define UTXH0 (*(volatile unsigned long *)0x50000020) //UART channel 0 transmit buffer register #define URXH0 (*(volatile unsigned long *)0x50000024) //UART channel 0 receive buffer register #define UBRDIV0 (*(volatile unsigned long *)0x50000028) //Baud rate divisior register 0 #define PCLK 50000000 //PCLK=50M (start.S中设置了 FCLK:HCLK:PCLK = 1:4:8, FCLK=400M) #define BAUD 115200 /******************************************************************* *函数名称:Uart_Init() *功能描述:UART初始化函数 *其他说明: *创建日期:2015.12.14 *******************************************************************/ void Uart_Init(void) { /*配置引脚功能*/ GPHCON &= (~(0xf << 4)); GPHCON |= (0xa << 4); //GPH2设为TXD0,GPH3设为RXD0 /*设置数据格式*/ ULCON0 = 0b11; //8位数据位,1位停止位,无奇偶校验 /*设置工作模式*/ UCON0 = 0b0101; //发送和接收均采用轮询方式 /*设置波特率*/ UBRDIV0 = (int)(PCLK/(BAUD*16) - 1); //波特率设置为115200 } /******************************************************************* *函数名称:Puts() *功能描述:字符发送函数 *输入形参:ch *返 回 值:无 *其他说明:ch为需要发送的字符 *创建日期:2015.12.14 *******************************************************************/ void Puts(unsigned char ch) { while (!(UTRSTAT0 & (1 << 2))); UTXH0 = ch; } /******************************************************************* *函数名称:Gets() *功能描述:字符接收函数 *输入形参:无 *返 回 值:ch *其他说明:ch为接收到的字符 *创建日期:2015.12.14 *******************************************************************/ unsigned char Gets(void) { char ch; while (!(UTRSTAT0 & (1 << 0))); ch = URXH0; return ch; } ~~~
';

Nand Flash裸机驱动设计

最后更新于:2022-04-01 16:11:39

Nand Flash型号 : K9F2G08U0A ## 1、以页方式读取Nand Flash中的数据 ①选中Nand Flash芯片; ②清除RnB; ③发送命令0x00; ④发送列地址(列地址两个周期,行地址三个周期); ⑤发送行地址(页号); ⑥发送命令0x30; ⑦等待RnB; ⑧读取RnB; ⑨取消选中Nand Flash芯片; ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-26_579724f8e5b4f.jpg) ## 2、以页方式向Nand Flash中写入数据 ①选中Nand Flash芯片; ②清除RnB; ③发送命令0x80; ④发送列地址;发送行地址; ⑤向Nand Flash写入数据; ⑥发送命令0x10; ⑦等待RnB; ⑧发送命令0x70; ⑨读取写入状态; ⑩取消选中Nand Flash; ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-26_579724f9301f2.jpg) ## 3、块擦除操作 ①选中Nand Flash芯片; ②清除RnB; ③发送命令0x60; ④发送行地址; ⑤发送命令0xD0; ⑥等待RnB; ⑦读取擦除状态; ⑧取消选中Nand Flash; ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-26_579724f9501b2.jpg) ## 4、K9F2G08U0A的阵列组织(即内部组成结构) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-26_579724f9746b3.jpg) ## 5、在srart.S中,需要调用Nand_Init函数对Nand Flash进行初始化,然后调用Nand_To_Ram函数将Nand Flash中的数据复制到SDRAM中。 ~~~ /******************************************************************* *版权所有(C)2015,ZJU * *文件名称:nand.c *内容摘要:关于NAND flash的配置 *其它说明:NAND flash型号: K9F2G08U0B * 开发板型号: TX2440 *当前版本:V1.0 *作 者:Frank *完成日期:2015.12.12 * *******************************************************************/ #define NFCONF (*(volatile unsigned long *)0x4E000000) //NAND flash configuration register #define NFCONT (*(volatile unsigned long *)0x4E000004) //NAND flash control register #define NFCMMD (*(volatile unsigned char *)0x4E000008) //NAND flash command set register #define NFADDR (*(volatile unsigned char *)0x4E00000C) //NAND flash address register #define NFDATA (*(volatile unsigned char *)0x4E000010) //NAND flash data register #define NFSTAT (*(volatile unsigned char *)0x4E000020) //NAND flash operation status register #define TACLS 1 #define TWRPH0 2 #define TWRPH1 1 /******************************************************************* *函数名称:Select_Chip() *功能描述:NAND flash使能函数 *其他说明:选中NAND flash(片选使能) *创建日期:2015.12.12 *******************************************************************/ void Select_Chip(void) { NFCONT &= ~(1 << 1); } /******************************************************************* *函数名称:Deselect_Chip() *功能描述:NAND flash禁止函数 *其他说明:取消选中NAND flash(片选禁止) *创建日期:2015.12.12 *******************************************************************/ void Deselect_Chip(void) { NFCONT |= (1 << 1); } /******************************************************************* *函数名称:Wait_RnB() *功能描述:等待RnB *其他说明:RnB为1时表示响应了 *创建日期:2015.12.12 *******************************************************************/ void Wait_RnB(void) { while (!(NFSTAT & (1 << 2))); } /******************************************************************* *函数名称:Clear_RnB() *功能描述:清除RnB *其他说明: *创建日期:2015.12.12 *******************************************************************/ void Clear_RnB(void) { NFSTAT |= (1 << 2); } /******************************************************************* *函数名称:Send_Cmd(unsigned char cmd) *功能描述:NAND flash命令发送 *输入参数:cmd *返 回 值:无 *其他说明:cmd为向NAND flash发送的命令字符 *创建日期:2015.12.12 *******************************************************************/ void Send_Cmd(unsigned char cmd) { NFCMMD = cmd; } /******************************************************************* *函数名称:Send_Addr(unsigned char addr) *功能描述:NAND flash地址发送函数 *输入参数:addr *返 回 值:无 *其他说明:addr为8位地址 *创建日期:2015.12.12 *******************************************************************/ void Send_Addr(unsigned char addr) { NFADDR = addr; } /******************************************************************* *函数名称:NF_PageRead(unsigned long addr, unsigned char * buff) *功能描述:读取NAND flash中整页的内容 *输入参数:addr, *buff *返 回 值:无 *其他说明:addr为所读取页的行地址,buff寄存器存储读取的NF中的内容 *创建日期:2015.12.12 *******************************************************************/ void NF_PageRead(unsigned long addr, unsigned char * buff) { int i = 0; Select_Chip(); //选中NAND flash芯片 Clear_RnB(); //清除RnB Send_Cmd(0x00); //发送命令0x00 Send_Addr(0x00); //发送列地址(列地址两个周期,行地址三个周期) Send_Addr(0x00); Send_Addr(addr & 0xff); //发送行地址(页号) Send_Addr((addr >> 8) & 0xff); Send_Addr((addr >> 16) & 0xff); Send_Cmd(0x30); //发送命令0x30 Wait_RnB(); //等待RnB for (i=0; i<2048; ++i) //读取数据 { buff[i] = NFDATA; } Deselect_Chip(); //取消选中NAND flash芯片 } /******************************************************************* *函数名称:NF_PageWrite(unsigned long addr, unsigned char * buff) *功能描述:以页的方式向NAND flash中写入数据 *输入参数:addr, *buff *返 回 值:ret *其他说明:addr为所写页的行地址,buff寄存器为向NF中写入的内容 *创建日期:2015.12.13 *******************************************************************/ int NF_PageWrite(unsigned long addr, unsigned char * buff) { int ret ; int i = 0; Select_Chip(); //选中NAND flash芯片 Clear_RnB(); //清除RnB Send_Cmd(0x80); //发送命令0x80 Send_Addr(0x00); //发送列地址 Send_Addr(0x00); Send_Addr(addr & 0xff); //发送行地址 Send_Addr((addr >> 8) & 0xff); Send_Addr((addr >> 16) & 0xff); for (i=0; i<2048; ++i) //向NAND flash写入数据 { NFDATA = buff[i]; } Send_Cmd(0x10); //发送命令0x10 Wait_RnB(); //等待RnB Send_Cmd(0x70); //发送命令0x70 ret = NFDATA; //读取写入状态 Deselect_Chip(); //取消选中NAND flash return ret; } /******************************************************************* *函数名称:NF_Erase(unsigned long addr) *功能描述:整块擦除NAND flash *输入参数:addr *返 回 值:ret *其他说明:addr为所擦除页的行地址,ret为擦除状态返回值 *创建日期:2015.12.13 *******************************************************************/ int NF_Erase(unsigned long addr) { int ret; Select_Chip(); //选中NAND flash芯片 Clear_RnB(); //清除RnB Send_Cmd(0x60); //发送命令0x60 Send_Addr(addr & 0xff); //发送行地址 Send_Addr((addr >> 8) & 0xff); Send_Addr((addr >> 16) & 0xff); Send_Cmd(0xD0); //发送命令0xD0 Wait_RnB(); //等待RnB Send_Cmd(0x70); //发送命令0x70 ret = NFDATA; //读取擦除状态 Deselect_Chip(); //取消选中NAND flash芯片 return ret; } /******************************************************************* *函数名称:Nand_Reset() *功能描述:复位NAND flash *其他说明: *创建日期:2015.12.12 *******************************************************************/ void Nand_Reset(void) { Select_Chip(); //选中NAND flash Clear_RnB(); //清除RnB Send_Cmd(0xff); //发送0xff命令 Wait_RnB(); //等待RnB Deselect_Chip(); //取消选中NAND flash } /******************************************************************* *函数名称:Nand_Init() *功能描述:初始化NAND flash *其他说明: *创建日期:2015.12.12 *******************************************************************/ void Nand_Init(void) { NFCONF = ((TACLS << 12) | (TWRPH0 << 8) | (TWRPH1 << 4)); //初始化NFCONF NFCONT = ((1 << 0) | (1 << 1)); //初始化NFCONT Nand_Reset(); //复位 } /******************************************************************* *函数名称:Nand_To_Ram(unsigned long , unsigned char * , int) *功能描述:读取NAND flash中整页的内容 *输入参数:start_addr, * sdram_addr, size *返 回 值:无 *其他说明:addr为所读取页的行地址,buff寄存器存储读取的NF中的内容 *创建日期:2015.12.12 *******************************************************************/ void Nand_To_Ram(unsigned long start_addr, unsigned char * sdram_addr, int size) { int i = 0; for (i=(start_addr>>11); size>0; ) //采用的是按页拷贝的方式,不需要列地址,只保留行地址 { NF_PageRead(i, sdram_addr); size -= 2048; sdram_addr += 2048; i++; } } ~~~
';

对((volatile unsigned long ))的理解

最后更新于:2022-04-01 16:11:37

最近在学习Nand Flash驱动程序设计时,涉及到((volatile unsigned long )),通过查阅部分网络文章,对其用法和指针有了进一步理解,遂作此笔记。本文参考了yueleilei的文章--ARM定义特殊寄存器(*(volatile unsigned long *))的理解[点击打开链接](http://bbs.ednchina.com/BLOG_ARTICLE_3002274.HTM),在此感谢。 ## 一、对 #define SREG (*(volatile unsigned char *)0x5F)的理解    嵌入式系统编程,要求程序员能够利用C语言访问固定的内存地址。既然是个地址,那么按照C语言的语法规则,这个表示地址的量应该是指针类型。所以,知道要访问的内存地址后,比如0x5F,第一步是要把它强制转换为指针类型(unsigned char *)0x5F,AVR的SREG是八位寄存器,所以0x5F强制转换为指向unsigned char类型。    (注意,这一步的理解很关键,很多文章说:( volatile unsigned long * )的意思是将后面的那个地址强制转换成 volatile unsigned long * ,当初看文章一直不理解这句话,其实解释为:将(volatile unsigned long * )后面跟的内容转化成一个指针,并且该指针指向一个易变的无符号整数,这样更易理解。)    volatile(可变的)这个关键字说明这变量可能会被意想不到地改变,这样编译器就不会去假设这个变量的值了。这种“意想不到地改变”,不是由程序去改变,而是由硬件去改变——意想不到。    第二步,对指针变量引用,就能操作指针所指向的地址的内容了        *(volatile unsigned CHAR *)0x5F    第三步,小心地把#define宏中的参数用括号括起来,这是一个很好的习惯,所以        #define SREG (*(volatile unsigned CHAR *)0x5F)    类似的,如果使用一个32位处理器,要对一个32位的内存地址进行访问,可以这样定义        #define RAM_ADDR (*(volatile unsigned LONG *)0x0000555F)    然后就可以用C语言对这个内存地址进行读写操作了        读:tmp = RAM_ADDR;        写:RAM_ADDR = 0x55; ## 二、举例    例:如何理解(*(volatile unsigned long *)0x56000010)    解答:        long是32位整型,unsigned指无符号数,左边的*表示取内容;        volatile表示易变的,告诉编译器不要优化,这个地址的内容不一定是在程序中改变的(可能是硬件上改变的,如寄存器中某些状态位的改变);        (volatile unsigned long *) 表示将后面跟的内容转化成一个指针,并且是指向一个易变的无符号整数。左边再加个,表示取该指针指向地址的内容。       总的意思是取那个内存单元(内存地址0x56000010)里存的数,并将这个数转化为无符号整数。
';

嵌入式学习路线与方法的一个不错的讲座

最后更新于:2022-04-01 16:11:35

## 一、嵌入式开发用到哪些知识 1、编程语言: 第一层次(C语言),第二层次(ARM汇编、shell脚本、C++、Java); 2、操作系统: 第一层次(linux),第二层次(Android、RTOS(一类实时操作系统,如ucos、uclinux等,一般用在需要操作系统的单片机上)); 3、硬件方面: 会看原理图,懂得串口、I2C、USB等常见通信设备的原理及编程、懂得LCD、触摸屏等常见元件原理及编程。 ## 二、嵌入式开发需要什么技能 1、以软件为主,但是需要对硬件有一定了解; 2、重在调试,需要有修改和调试程序的能力; ## 三、学习体系 1、嵌入式核心课程 2、Android扩展 3、物联网扩展 4、各种实训项目 ## 总结: ①嵌入式是处理“软硬结合”部分的; ②嵌入式软件开发并不需要会设计硬件电路和自己画PCB板; ③嵌入式软件开发以C语言和linux系统为核心,学习的关键和入口点就在这里; ④嵌入式开发涉及面极广,学习周期长,学习难度大。 ## 四、嵌入式核心课程(5大模块) 1、linux基础  +  C语言; 2、linux应用程序开发(系统编程、网络编程); 3、ARM编程(ARM体系架构、ARM汇编、开发板常见外设裸机编程); 4、linux系统移植(uboot移植、kernel移植、rootfs制作); 5、linux驱动开发。 ## 五、Android扩展(3大模块) 1、Android HAL驱动; 2、Android系统定制; 3、Android应用开发; ## 六、物联网扩展(无线扩展) 1、GPS和地图查询服务; 2、wifi; 3、蓝牙4.0; 4、Zigbee; 5、RFID. 讲座内容来自朱有鹏老师的 《嵌入式工程师养成计划--嵌入式软件工程师完全学习指南》,在此感谢^_^
';

S3C2440 外部按键中断解析

最后更新于:2022-04-01 16:11:33

学习bootloader制作的过程中,学到 “通过按键进入中断控制LED亮灭”的实验时,自己所用的开发板和视频讲解中的不同,于是琢磨了一下中断涉及到的各个寄存器,并进行编码尝试,最终完成了实验,达到了通过按键以中断方式控制LED亮灭的目的。2440属于非向量中断方式,和6410、210的向量中断方式对于中断的处理有一些不同,因此本文的讲解并不完全适合6410和210。 ## 一、概念 中断分为两大类:外部中断和内部中断。 1、外部中断:S3C2440的24个外部中断占用GPF0~GPF7(EINT0~EINT7)、                                                 GPG0~GPG15(EINT8~EINT23)。使用这些引脚作为中断输入时,必须将引脚配置为EINT模式,配置方法可参考datasheet。 2、内部中断:内部中断包括DMA中断、UART中断、IIC中断等等由内部外设触发的中断。 3、相关寄存器:S3C2440中断控制涉及到10个寄存器-- SRCPND、INTMOD、INTMSK、PRIORITY、INTPND、INTOFFSET、SUBSRCPND、INTSUBMSK、EINTMASK、EINTPEND,这10个寄存器的定义及其功能描述如下表一。对中断的控制无外乎配置和处理这10个寄存器中的某几个。                                   表一  与S3C2440中断相关的10个寄存器的信息 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-26_579724f870aeb.jpg) 4、各寄存器的关系(工作流程)。根据中断源进行分类,中断的处理流程可用下图1表示: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-26_579724f89867b.jpg) 图1  S3C2440中断处理流程图  由上图1可知,S3C2440的中断可分为四种情况:由外部中断源(EINT0~EINT3)触发的中断、由外部中断子中断源(EINT4~EINT23)触发的中断、由内部中断源(内部子中断)触发的中断和由内部中断源(非子中断)触发的中断。 5、中断的开启(中断初始化,INTMOD 和 PRTORITY使用默认值) (a)如果是外部中断(EINT0~EINT3)和内部中断(不带子中断),需设置INTMSK,让它不屏蔽中断即可; (b)如果是带子中断的内部中断,需设置INTSUBMSK 和 INTMSK,让它们不屏蔽中断即可; (c)如果是外部中断(EINT4~EINT23),需设置EINTMASK 和 INTMSK,让它们不屏蔽中断即可; 注意:CPSR中的第7位I也需清除(在start.S中关闭了中断,这一步是针对在bootloader设计中进行EINT实验时的操作) 6、中断处理流程 (a)如果是外部中断(EINT0~EINT3)和 不带子中断的内部中断,发生中断后SRCPND相应位置1,如果没有被 INTMSK屏蔽,那么等待进一步处理; (b)如果是带子中断的内部中断,发生中断后SUBSRCPND相应位置1,如果没有被INTSUBMSK屏蔽,则SRCPND相应位置1,如果没有被INTMSK屏蔽,那么等待进一步处理; (c)如果是外部中断(EINT4~EINT23),发生中断后EINTPEND相应位置1,如果没有被EINTMASK屏蔽,则SRCPND相应位EINT4-7和EINT8~23置1,如果没有被INTMSK屏蔽,那么等待进一步处理;  三种中断都等待进一步处理了,接下来从SRCPND继续往前看,看看INTMSK,如果中断被屏蔽了,就不用说了(注意:快中断也能被屏蔽)。如果没有被屏蔽,那么会进一步到INTMOD。如果是快中断,那么直接出来,进入FIQ(即CPU进入快中断模式处理)。如果是普通中断,那么SRCPND可以有多位置1(FIQ只能有一个),这时就会经过PRIORITY选出一个优先级高的,然后根据选出的中断把INTPND相应位置1(注意:只能选出一个),进入IRQ,让CPU处理。  INTOFFSET寄存器用来表示INTPND中哪一位置1了,可以用来判断请求中断的中断源,但是,对于外部中断EINT4~EINT23是无法判断的,如EINT4~EINT7中任何一个中断源请求中断,都会将INTOFFSET中的位EINT4_7置1,所以要判断具体是哪个中断源请求的中断,可读取EINTPEND中的值进行判断。 7、中断的清除 (a)如果是外部中断EINT0~EINT3和不带子中断的内部中断,只需清除SRCPND(注意:清除时对相应位写“1”); (b)如果是带子中断的内部中断,需清除SRCPND和SUBSRCPND,注意先清除SUBSRCPND,再清除SRCPND。因为如果先清除SRCPND的话,在清除SUBSRCPND的过程中,SRCPND会以为又有中断发生,又会置1,也就是说一次中断会响应两次,所以必须先掐断源头,对它们同样是写“1”清除 (c)如果是外部中断EINT4~EINT23,需清除EINTPEND和SRCPND(同样注意顺序),写“1”清除。 ## 二、按键中断实验 1、所使用开发板的按键与芯片连接示意如下图2,其中KEY1 --> GPF4, KEY2--> GPF5,KEY3 --> GPF6,KEY4 --> GPF7。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-26_579724f8b6162.jpg) 图2  按键与S3C2440连接示意 通过查阅s3c2440的datasheet可知,GPF4~GPF7对应外部中断EINT4~EINT7。所以对于中断初始化,需设置寄存器EINTMASK和INTMSK,取消中断屏蔽。中断处理过程中,可通过阅读EINTPEND寄存器的值判定触发中断的中断源。中断清除时,向EINTPEND和SRCPND中相应位写“1”,清除中断(注意顺序)。以下为实验的源代码: ~~~ /*interrupt registes*/ #define SRCPND (volatile unsigned long *)0x4a000000 //Interrupt request status #define INTMOD (volatile unsigned long *)0x4a000004 //Interrupt mode control #define INTMSK (volatile unsigned long *)0x4a000008 //Interrupt mask control #define PRIORITY (volatile unsigned long *)0x4a00000c //IRQ priority control #define INTPND (volatile unsigned long *)0x4a000010 //Interrupt request status #define INTOFFSET (volatile unsigned long *)0x4A000014 //Interrupt request source offset #define SUBSRCPND (volatile unsigned long *)0x4A000018 //Sub source pending #define INTSUBMSK (volatile unsigned long *)0x4A00001c //Interrupt sub mask #define EINTMASK (volatile unsigned long *)0x560000a4 //External interrupt mask register #define EINTPEND (volatile unsigned long *)0x560000a8 //External interrupt pending register /******************************************************************* *函数名称:init_irq() *功能描述:中断初始化(取消中断屏蔽) *其他说明:按键中断对应的是外部中断EINT4~7,所以设置EINTMASK、INTMSK *修改日期 版本号 修改人 修改内容 *------------------------------------------------------------------ *2015.12.5 V1.0 *******************************************************************/ void init_irq() { *(EINTMASK) &= ((~(1 << 4)) & (~(1 << 5)) & (~(1 << 6)) & (~(1 << 7))); //取消EINT4~7的子中断屏蔽(注意,这步必须在后面一步之前) *(INTMSK) &= (~(1 << 4)); //取消EINT4~7的中断屏蔽 /***清除CPSR寄存器中的第7位I(IRQ disable),因为在start.S中关闭了中断****/ __asm__( "mrs r0, cpsr\n" "bic r0, r0, #0x80\n" "msr cpsr_c, r0\n" : : ); } /******************************************************************* *函数名称:handle_int() *功能描述:中断处理函数 *其他说明: *修改日期 版本号 修改人 修改内容 *------------------------------------------------------------------ *2015.12.6 V1.0 *******************************************************************/ void handle_int() { /*判断产生中断的中断源*/ unsigned long value = *(INTOFFSET); unsigned long value_offset = *(EINTPEND); //value_offset的值分别对应EINT4~EINT7 if (4 == value) //value = 4 表明EINT4 ~ EINT7请求中断 (这个条件不是必须的,可直接判断value_offset) { switch (value_offset) { case 0x00000010 : //EINT4 --> k1 led_on(); break; case 0x00000020 : //EINT5 --> k2 led_on(); break; case 0x00000040 : //EINT6 --> k3 led_off(); break; case 0x00000080 : //EINT7 --> k4 led_off(); break; default : break; } } /*清除中断标志*/ *(EINTPEND) = value_offset; //把EINTPEND中当前值重新赋给EINTPEND,即相当于对相应位置1清除(不过这 //样做的前提是可以明确只发生一个中断,不然有可能将其他的中断请求清除) *(INTPND) = 1 << 4; } ~~~ 参考文章:http://blog.chinaunix.net/uid-25100840-id-351208.html
';

前言

最后更新于:2022-04-01 16:11:30

> 原文出处:[嵌入式linux与ARM学习](http://blog.csdn.net/column/details/luckylinux.html) 作者:[lnf_2373837248](http://blog.csdn.net/lnf_2373837248) **本系列文章经作者授权在看云整理发布,未经作者允许,请勿转载!** # 嵌入式linux与ARM学习 > linux与ARM学习中的一些技术心得和笔记,部分文章也涉及单片机、电子电路等知识。技术是在交流中不断进步的,各位看官,谬误之处不吝赐教,以助小弟成长!^_^
';