ADC的基本原理及编写基于ARM的裸机程序的方案解析

一口Linux
关注

int main (void)

 unsigned char bit4,bit3,bit2,bit1;
 unsigned int temp = 0;
 
 uart_init();
 adc_init(temp);
 puts("开始转换");
 while(1)
 {
   while(!(ADCCON & 0x8000));
   temp = ADCDAT & 0xfff;
   printf("U = %d",temp);
   temp = 1.8 * 1000 * temp/0xfff;
   bit4 = temp /1000;
   putc(table[bit4]);
   bit3 = (temp % 1000)/100?;
   putc(table[bit3]);
   bit2 = ((temp % 1000)%100)/10;
   putc(table[bit2]);
   bit1 = ((temp % 1000)%100)%10;
   putc(table[bit1]);
   puts("mV");
   putc('');
   mydelay_ms(1000);
 }
 return 0;

中断模式

中断模式读取数据步骤如下:

1.要读取数据首先向ADC寄存器ADCCON的bit:0写1,发送转换命令;2.当ADC控制器转换完毕会通过中断线向CPU发送中断信号;3.在中断处理函数中,读走数据,并清中断.

注:中断对应寄存器的设置,后续会更新对应的文档。

void do_irq(void)

      int irq_num;
      irq_num = CPU0.ICCIAR &0x3ff;
      switch(irq_num)
      {
        case 42:
             adc_num = ADCDAT&0xfff;
             printf("adc = %d",adc_num);
             CLRINTADC = 0;
      //    IECR2 = IECR2 | (1 << 19);               打开的话只能读取一次,
             //42/32
             ICDICPR.ICDICPR1 = ICDICPR.ICDICPR1 | (1 << 10);【清GIC中断标志位类似于 ICDISER】
             break;
      }
      CPU0.ICCEOIR = CPU0.ICCEOIR & (~0x3ff) | irq_num;

void adc_init(void)
{    //12bit   使能分频       分频值                 手动
      ADCCON = (1 << 16) | (1 << 14) | (0xff << 6) | (1 << 0);
      ADCMUX = 3;

void adcint_init(void)

      IESR2 = IESR2 | (1 << 19);
      ICDDCR = 1;    //使能分配器
      //42/32
      ICDISER.ICDISER1 = ICDISER.ICDISER1 | (1 << 10);//使能相应中断到分配器
      ICDIPTR.ICDIPTR10 = ICDIPTR.ICDIPTR10 &(~(0xff << 16)) | (0x1 << 16);//发送到相应CPU接口
      CPU0.ICCPMR = 255;//设置中断屏蔽优先级
      CPU0.ICCICR = 1;  //全局使能开关

int main (void)

 adc_init();
      adcint_init();
      while(1)
      {
             ADCCON = ADCCON | 1;
             delay_ms(1000);
      }
  return 0;

基于Linux驱动编写设备树

编写基于Linux的ADC外设驱动,首先需要编写设备树节点信息,在裸机程序中,我们只用到了寄存器地址,而编写基于Linux的驱动,我们需要用到中断功能。所以编写设备树节点需要知道ADC要用到的硬件资源主要包括:寄存器资源和中断资源。

关于中断的使用我们在后续文章中会继续分析,现在我们只需要知道中断信息如何填写即可。

ADC寄存器信息填写

在这里插入图片描述

由上可知,寄存器基地址为0x126c0000,其他寄存器只需要根据基地址做偏移即可获取,所以设备树的reg属性信息如下:

   reg = <0x126C0000 0x20>;
ADC中断信息填写

描述中断连接需要四个属性:父节点提供以下信息

interrupt-controller - 一个空的属性定义该节点作为一个接收中断信号的设备。
interrupt-cells      - 这是一个中断控制器节点的属性。它声明了该中断控制器的中断指示符中【interrupts】 cell 的个数(类似于 #address-cells 和 #size-cells)。

子节点描述信息

interrupt-parent - 这是一个设备节点的属性,包含一个指向该设备连接的中断控制器的 phandle。那些没有 interrupt-parent 的节点则从它们的父节点中继承该属性。
interrupts       - 一个设备节点属性,包含一个中断指示符的列表,对应于该设备上的每个中断输出信号。【设备的中断信息放在该属性中】

父节点

首先我们必须知道ADC控制器的中断线的父节点:

由上图可知ADC控制器位于soc内,4个ADC通道公用一根中断线,该中断线连接在combiner上,所以我们需要查找到combiner这个父节点的说明:

进入设备树文件所在目录:archrmootdts

grep combiner *.* -n

经过筛选得到以下信息,

因为我们使用的板子是exynos4412,而exynos系列通用的平台设备树文件是exynos4.dtsi,查看该文件:

上图列举了combiner控制器的详细信息:

   interrupt-cells ;
   interrupt-cells =<2>;

所以ADC控制器中断控制器的interrupts属性应该有两个cell。

interrupts属性填写

而设备的中断信息填写方式由内核的以下文档提供:

Documentationdevicetreeindingsinterrupt-controllerinterrupts.txt
69. b) two cells
70.  ------------
71.  The #interrupt-cells property is set to 2 and the first cell 72. defines the
73.  index of the interrupt within the controller, while the second cell is used
74.  to specify any of the following flags:
75.    - bits[3:0] trigger type and level flags
76.        1 = low-to-high edge triggered
77.        2 = high-to-low edge triggered
78.        4 = active high level-sensitive
79.        8 = active low level-sensitive

由以上信息可知,中断的第一个cell是该中断源所在中断控制器的index,第二个cell表示中断的触发方式

*. 1:上升沿触发*. 2:下降沿触发*. 3:高电平触发*. 4:低电平触发

那么index应该是多少呢?

详见datasheet的9.2.2 GIC Interrupt Table 节:

此处我们应该是填写左侧的SPI ID:10 还是填写INTERRUPT ID:42呢?

此处我们可以参考LCD节点的interrupts填写方法:

通过查找父节点为combiner的设备信息。

继续grep combiner . -n

由此可见lcd这个设备的interrupts属性index值是11,所以可知ADC控制器中断线的index是10。中断信息如下:

interrupt-parent = <&combiner>;
interrupts = <10 3>;

ADC外设设备树信息

fs4412-adc{
   compatible = "fs4412,adc";
   reg = <0x126C0000 0x20>;
   interrupt-parent = <&combiner>;
   interrupts = <10 3>;
};

本文默认大家会使用设备树,不知道如何使用设备树的朋友,后续会开一篇单独讲解设备树。【注意】在不支持设备树内核中,以Cortex-A8为例,中断信息填写在以下文件中

内部中断,Irqs.h (archrmmach-s5pc100includemach)
外部中断在Irqs.h (archrmplat-s5pincludeplat)

ADC属于内部中断,位于archrmmach-s5pc100includemachIrqs.h中。

寄存器信息填写在以下位置:

archrmmach-s5pc100Mach-smdkc100.c
static struct platform_device *smdkc100_devices[] __initdata = {
 &s3c_device_adc,
 &s3c_device_cfcon,
 &s3c_device_i2c0,
 &s3c_device_i2c1,
 &s3c_device_fb,
 &s3c_device_hsmmc0,
 &s3c_device_hsmmc1,
 &s3c_device_hsmmc2,
 &samsung_device_pwm,
 &s3c_device_ts,
 &s3c_device_wdt,
 &smdkc100_lcd_powerdev,
 &s5pc100_device_iis0,
 &samsung_device_keypad,
 &s5pc100_device_ac97,
 &s3c_device_rtc,
 &s5p_device_fimc0,
 &s5p_device_fimc1,
 &s5p_device_fimc2,
 &s5pc100_device_spdif,
};

声明: 本文由入驻OFweek维科号的作者撰写,观点仅代表作者本人,不代表OFweek立场。如有侵权或其他问题,请联系举报。
侵权投诉

下载OFweek,一手掌握高科技全行业资讯

还不是OFweek会员,马上注册
打开app,查看更多精彩资讯 >
  • 长按识别二维码
  • 进入OFweek阅读全文
长按图片进行保存