[APM32F4] 基于APM32F4的ADC采集VGA信号的实现方案

[复制链接]
 楼主| Peixu 发表于 2024-12-4 15:10 | 显示全部楼层 |阅读模式
本帖最后由 Peixu 于 2024-12-4 15:21 编辑

1. VGA信号的基本概念
VGA信号包括三个主要部分:
**RGB信号**:分别代表红色、绿色和蓝色的模拟信号,这些信号的电平决定了显示图像的颜色。
**水平同步信号(HSYNC**:在每行像素结束时,提供一个短脉冲信号,指示显示设备开始新的一行。
**垂直同步信号(VSYNC**:在一帧结束时提供脉冲信号,指示显示设备开始新的一帧。
对于1920x1080分辨率的60Hz显示,VGA信号的有效采样时间和采样率计算如下:
每行有效像素时间为12.92微秒。
每行采集的像素为40个,因此每个像素的采样时间为323纳秒。
所以在我们在这12.82us的时间尽可能用ADC去多采集信号。这样才能达到更好的效果。

2. 设计思路
要实现VGA信号的ADC采集,主要步骤如下:
**信号处理**:通过电路设计,将VGA信号的RGB信号和同步信号连接到APM32F4ADC引脚,并进行必要的电平转换。
**ADC配置**:设置APM32F4ADC参数,以便进行高速采样。
**DMA配置**:为了提高数据传输的效率,将ADC采集的数据通过DMA(直接存储器访问)方式传送至内存。
**外部中断处理**:使用外部中断来触发ADC采集,以确保在每个HSYNC信号到来时进行采样。
**数据处理**:在主循环中处理采集的数据,进行显示或存储。

3. 硬件连接
3.1 信号连接
VGA信号的RGB信号和同步信号连接至APM32F4ADC引脚和外部中断引脚:
**R信号**:连接至ADC通道0PA3)。
**G信号**:连接至ADC通道1PA4)。
**B信号**:连接至ADC通道2PA5)。
**HSYNC信号**:连接至外部中断(PC10)。
**VSYNC信号**:连接至另一个外部中断(PC11)。

3.2 电路设计
在连接VGA信号和APM32F4之间,建议使用以下电路设计:
**低通滤波器**:在ADC输入引脚前添加低通滤波器,以减少高频干扰。
**电平转换电路**:确保输入信号在APM32F4ADC输入范围内(通常是0-3.3V)。

4. 软件实现
4.1 ADC初始化
配置ADC以采集RGB信号:
  1. void ADC_Init(void) {
  2.     GPIO_Config_T gpioConfig;
  3.     ADC_Config_T adcConfig;
  4.     ADC_CommonConfig_T adcCommonConfig;

  5.     RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOA);

  6.     // GPIO配置
  7.     GPIO_ConfigStructInit(&gpioConfig);
  8.     gpioConfig.mode = GPIO_MODE_AN;
  9.     gpioConfig.pupd = GPIO_PUPD_NOPULL;
  10.     gpioConfig.pin = GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5;
  11.     GPIO_Config(GPIOA, &gpioConfig);

  12.     RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_ADC1);
  13.     ADC_Reset();

  14.     // ADC通用配置
  15.     adcCommonConfig.mode = ADC_MODE_INDEPENDENT;
  16.     adcCommonConfig.prescaler = ADC_PRESCALER_DIV2;
  17.     ADC_CommonConfig(&adcCommonConfig);

  18.     // ADC配置
  19.     adcConfig.resolution = ADC_RESOLUTION_12BIT;
  20.     adcConfig.scanConvMode = DISABLE; // 单通道
  21.     adcConfig.continuousConvMode = ENABLE; // 连续模式
  22.     adcConfig.dataAlign = ADC_DATA_ALIGN_RIGHT;
  23.     adcConfig.extTrigEdge = ADC_EXT_TRIG_EDGE_FALLING;
  24.     adcConfig.extTrigConv = ADC_EXT_TRIG_CONV_EINT_11; // 触发方式为外部中断
  25.     adcConfig.nbrOfChannel = 1;
  26.     ADC_Config(ADC1, &adcConfig);
  27.    
  28.     // 配置ADC通道
  29.     ADC_ConfigRegularChannel(ADC1, ADC_CHANNEL_3, 1, ADC_SAMPLETIME_3CYCLES); // R
  30.     ADC_ConfigRegularChannel(ADC1, ADC_CHANNEL_4, 1, ADC_SAMPLETIME_3CYCLES); // G
  31.     ADC_ConfigRegularChannel(ADC1, ADC_CHANNEL_5, 1, ADC_SAMPLETIME_3CYCLES); // B
  32. }

4.2 DMA初始化为ADC配置DMA:
  1. void DMA_Init(void)
  2. {
  3.     DMA_Config_T dmaConfig;

  4.     RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_DMA2);

  5.     dmaConfig.peripheralBaseAddr = ADC_DR_ADDR;
  6.     dmaConfig.memoryBaseAddr = (uint32_t)R[0];  // 初始地址指向第一行
  7.     dmaConfig.dir = DMA_DIR_PERIPHERALTOMEMORY;
  8.     dmaConfig.bufferSize = SAMPLES_PER_CHANNEL;  // 每次传输的数据量
  9.     dmaConfig.peripheralInc = DMA_PERIPHERAL_INC_DISABLE;
  10.     dmaConfig.memoryInc = DMA_MEMORY_INC_ENABLE;
  11.     dmaConfig.peripheralDataSize = DMA_PERIPHERAL_DATA_SIZE_HALFWORD;
  12.     dmaConfig.memoryDataSize = DMA_MEMORY_DATA_SIZE_HALFWORD;

  13.     dmaConfig.loopMode = DMA_MODE_CIRCULAR;  // 使用普通模式
  14.     dmaConfig.priority = DMA_PRIORITY_HIGH;
  15.     dmaConfig.fifoMode = DMA_FIFOMODE_DISABLE;
  16.     dmaConfig.fifoThreshold = DMA_FIFOTHRESHOLD_HALFFULL;
  17.     dmaConfig.memoryBurst = DMA_MEMORYBURST_SINGLE;
  18.     dmaConfig.peripheralBurst = DMA_PERIPHERALBURST_SINGLE;
  19.     dmaConfig.channel = DMA_CHANNEL_0;        
  20.                
  21.     DMA_Config(DMA2_Stream0, &dmaConfig);
  22.     DMA_EnableInterrupt(DMA2_Stream0, DMA_INT_TCI**);  // 开启传输完成中断
  23.     DMA_Enable(DMA2_Stream0);  // 启用 DMA
  24. }
4.3 外部中断处理使用外部中断处理HSYNC信号:
  1. void EINT15_10_IRQHandler(void) {
  2.     if (EINT_ReadIntFlag(EINT_LINE_10)) {
  3.     /* 启动 ADC DMA 采集         */                                       
  4.     ADC1->STS = ~(uint32_t)ADC_FLAG_OVR;
  5.     ADC1->CTRL2_B.REGSWSC = BIT_SET;                        
  6.     while(RESET == DMA_ReadStatusFlag(DMA2_Stream0, DMA_FLAG_TCI**0));
  7.     DMA_ClearStatusFlag(DMA2_Stream0, DMA_FLAG_TCI**0);               
  8.     DMA2_Stream0->SCFG_B.EN = DISABLE;
  9.                                  
  10.     dmaCompleteFlag = 1;
  11.     HSync_cnt ++;
  12.                         

  13.     currentRow++;  // 切换到下一行 //
  14.     if (currentRow >= HSync_MAX)
  15.      {
  16.         currentRow = 0;  // 重置行号
  17.     }
  18.     DMA_ClearIntFlag(DMA2_Stream0, DMA_INT_TCI**0);
  19.     DMA_Switch(currentChannel,currentRow);                    
  20.     EINT_ClearIntFlag(EINT_LINE_10);        
  21.     }

  22.     if (EINT_ReadIntFlag(EINT_LINE_11)) {
  23.         currentChannel++;
  24.         if (currentChannel >= 3) currentChannel = 0; // 切换通道
  25.         ADC_SwitchChannel(currentChannel);
  26.         EINT_ClearIntFlag(EINT_LINE_11);
  27.     }
  28. }


4.4 数据处理在主循环中,处理采集到的数据:
  1. int main(void) {
  2.     // 初始化相关模块
  3.     USART_Init();
  4.     ADC_Init();
  5.     DMA_Init();
  6.     APM_PBInit(BUTTON_KEY2, BUTTON_MODE_EINT);                //中断行 PC10
  7.     APM_PBInit(BUTTON_KEY1, BUTTON_MODE_EINT);                //中断场 PC11
  8.     while (1) {
  9.         if (dmaCompleteFlag)
  10.         {
  11.             dmaCompleteFlag = 0;                                       
  12.             /* 处理采集到的数据 */
  13.             if (currentChannel == 0){
  14.             for (uint16_t row = 0; row < HSync_MAX; row++)
  15.                 {
  16.                     for (uint16_t i = 0; i < SAMPLES_PER_CHANNEL; i++)
  17.                     {
  18.                     printf("R[%d][%d] %d\r\n", row,i, R[row][i]);
  19.                     }
  20.                 }
  21.             }
  22.                
  23.             if (currentChannel == 1){

  24.             }
  25.                                        
  26.             if (currentChannel == 2){

  27.             }                        
  28.               printf("\r\n");                                       
  29.             }        
  30.                 }                                
  31. }
通过上述步骤,可以成功地使用APM32F4微控制器采集VGA信号。具体的使用可能需要根据特定需求对代码进行适当的修改和优化,以实现更好的性能和数据处理能力。通过采集VGA信号,可以为后续的图像处理、显示和分析提供数据支持。希望本方案能为您的项目提供参考和借鉴。



您需要登录后才可以回帖 登录 | 注册

本版积分规则

32

主题

58

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部

32

主题

58

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部