打印
[APM32F4]

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

[复制链接]
70|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Peixu|  楼主 | 2024-12-4 15:10 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 Peixu 于 2024-12-4 15:21 编辑

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

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

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

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

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

    RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOA);

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

    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_ADC1);
    ADC_Reset();

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

    // ADC配置
    adcConfig.resolution = ADC_RESOLUTION_12BIT;
    adcConfig.scanConvMode = DISABLE; // 单通道
    adcConfig.continuousConvMode = ENABLE; // 连续模式
    adcConfig.dataAlign = ADC_DATA_ALIGN_RIGHT;
    adcConfig.extTrigEdge = ADC_EXT_TRIG_EDGE_FALLING;
    adcConfig.extTrigConv = ADC_EXT_TRIG_CONV_EINT_11; // 触发方式为外部中断
    adcConfig.nbrOfChannel = 1;
    ADC_Config(ADC1, &adcConfig);
   
    // 配置ADC通道
    ADC_ConfigRegularChannel(ADC1, ADC_CHANNEL_3, 1, ADC_SAMPLETIME_3CYCLES); // R
    ADC_ConfigRegularChannel(ADC1, ADC_CHANNEL_4, 1, ADC_SAMPLETIME_3CYCLES); // G
    ADC_ConfigRegularChannel(ADC1, ADC_CHANNEL_5, 1, ADC_SAMPLETIME_3CYCLES); // B
}

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

    RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_DMA2);

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

    dmaConfig.loopMode = DMA_MODE_CIRCULAR;  // 使用普通模式
    dmaConfig.priority = DMA_PRIORITY_HIGH;
    dmaConfig.fifoMode = DMA_FIFOMODE_DISABLE;
    dmaConfig.fifoThreshold = DMA_FIFOTHRESHOLD_HALFFULL;
    dmaConfig.memoryBurst = DMA_MEMORYBURST_SINGLE;
    dmaConfig.peripheralBurst = DMA_PERIPHERALBURST_SINGLE;
    dmaConfig.channel = DMA_CHANNEL_0;        
               
    DMA_Config(DMA2_Stream0, &dmaConfig);
    DMA_EnableInterrupt(DMA2_Stream0, DMA_INT_TCI**);  // 开启传输完成中断
    DMA_Enable(DMA2_Stream0);  // 启用 DMA
}
4.3 外部中断处理使用外部中断处理HSYNC信号:
void EINT15_10_IRQHandler(void) {
    if (EINT_ReadIntFlag(EINT_LINE_10)) {
    /* 启动 ADC DMA 采集         */                                       
    ADC1->STS = ~(uint32_t)ADC_FLAG_OVR;
    ADC1->CTRL2_B.REGSWSC = BIT_SET;                        
    while(RESET == DMA_ReadStatusFlag(DMA2_Stream0, DMA_FLAG_TCI**0));
    DMA_ClearStatusFlag(DMA2_Stream0, DMA_FLAG_TCI**0);               
    DMA2_Stream0->SCFG_B.EN = DISABLE;
                                 
    dmaCompleteFlag = 1;
    HSync_cnt ++;
                        

    currentRow++;  // 切换到下一行 //
    if (currentRow >= HSync_MAX)
     {
        currentRow = 0;  // 重置行号
    }
    DMA_ClearIntFlag(DMA2_Stream0, DMA_INT_TCI**0);
    DMA_Switch(currentChannel,currentRow);                    
    EINT_ClearIntFlag(EINT_LINE_10);        
    }

    if (EINT_ReadIntFlag(EINT_LINE_11)) {
        currentChannel++;
        if (currentChannel >= 3) currentChannel = 0; // 切换通道
        ADC_SwitchChannel(currentChannel);
        EINT_ClearIntFlag(EINT_LINE_11);
    }
}


4.4 数据处理在主循环中,处理采集到的数据:
int main(void) {
    // 初始化相关模块
    USART_Init();
    ADC_Init();
    DMA_Init();
    APM_PBInit(BUTTON_KEY2, BUTTON_MODE_EINT);                //中断行 PC10
    APM_PBInit(BUTTON_KEY1, BUTTON_MODE_EINT);                //中断场 PC11
    while (1) {
        if (dmaCompleteFlag)
        {
            dmaCompleteFlag = 0;                                       
            /* 处理采集到的数据 */
            if (currentChannel == 0){
            for (uint16_t row = 0; row < HSync_MAX; row++)
                {
                    for (uint16_t i = 0; i < SAMPLES_PER_CHANNEL; i++)
                    {
                    printf("R[%d][%d] %d\r\n", row,i, R[row][i]);
                    }
                }
            }
               
            if (currentChannel == 1){

            }
                                       
            if (currentChannel == 2){

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



使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

26

主题

52

帖子

0

粉丝