ESM7000异构CPU实时应用之一
8通道并行100K 16bit AD采集

 2021-5-11     作者:刘乾坤    

  高速数据采集是对系统实时响应处理能力的考验,以实现100kSPS采样率的AD转换为例,系统需要每10μs稳定可靠的响应AD中断、读取AD数据。常规的WinCE或Linux嵌入式操作系统均无法满足稳定的10μs中断响应的性能要求,因此传统的高速数据采集方案通常使用FPGA/CPLD对AD芯片进行直接操作、控制AD转换并对数据进行缓存,缓存一定量的数据后再向系统发出中断请求,系统响应中断读取批量数据。传统的FPGA/CPLD方案实现复杂、成本较高,本文将介绍基于ESM7000工控主板实现的高效低成本高速AD采集方案。


  ESM7000是英创基于i.MX7D处理器开发的低功耗高性能工控主板,支持双网口、6串口、双CAN总线接口、PCIe、ISA总线等丰富的通讯接口,支持18-bit并行RGB或LVDS显示接口。主CPU i.MX7D是NXP推出的异构多核处理器,配置了主频高达1GHz的ARM Cortex-A7双核和一颗运行速度240MHz、带硬件浮点运算的ARM Cortex-M4内核。本方案将充分利用i.MX7D的异构CPU架构,由高性能的Cortex-A7完成人机交互、数据处理、通讯管理等复杂运算,而实时的AD数据采集则由i.MX7D的Cortex-M4完成。


  AD芯片选择了TI的ADS8588S,ADS8588S是单电源供电的、具有双极性输入的16位、高速8通道同步AD采样芯片,ADS8588S集成了模拟前端,允许直接连接传感器,无需使用外部驱动电路,能实现高性能、高精度及零延迟的AD转换,非常适用于工业自动化应用。


  下图是ESM7000连接ADS8588S的原理框图:


ESM7000异构CPU实时应用之一.png

图1:ESM7000连接ADS8588S原理框图


  ESM7000与ADS8588S的电路连接十分简单,ADS8588S的CONV启动AD转换信号由ESM7000的PWM3提供,ADS8588S的ADC_BUSY信号连接到ESM7000的GPIO25,可以作为转换完成的中断请求。ADS8588S的所有配置都由外部硬件完成,不需要软件配置,因为只需要3条SPI信号线,ESM7000的SPI_MOSI则被配置为GPIO作为ADS8588S硬件复位信号。为了实现高速可靠的实时响应,上述功能接口都由ESM7000的Cortex-M4内核管理使用。


  下表1列出了ADS8588S的AD转换时间,图2是读取ADS8588S AD转换结果的时序要求。


ESM7000异构CPU实时应用之一.png

表1:ADS8588S AD转换时间


ESM7000异构CPU实时应用之一.png

图2:ADS8588S读取数据时序


  ADS8588S SPI接口时钟最高为20MHz,读取8通道16位AD数据需要128个SPI时钟,最短耗时6.4μs,表1中ADS8588S最快的AD转换需要3.9μs,如果采用图2中的Read After conversion时序,则AD转换加上读取转换结果最少需要10.3μs,不能实现100kSPS的AD采集。如果在AD转换的同时读取上一次AD转换的结果(Read During Conversion),则要求SPI读操作必须在ADS8588S BUSY过程中完成,如图2所示。ADS8588S SPI读操作最快需要6.4μs,显然无法在3.9μs的AD转换时间内完成,但ADS8588S提供了一个2次平均模式,AD转换时间在8.4μs~8.8μs之间(见表1: Oversampling by 2),在此期间刚好可完成6.4μs的SPI读操作,而8.8μs的AD转换时间也能满足100kSPS的最大采样率的要求。


  下图是在ESM7000 Cortex-M4内核上、运行FreeRTOS操作系统实现的100kSPS AD数据采集实际波形,示波器通道1至通道4依次为:PWM3、ADC_BUSY、SPI_CS_B、SPI_SCLK。


ESM7000异构CPU实时应用之一.png

图3:ESM7000操作ADS8288S时序图


  上图在Cortex-M4程序中直接利用了ESM7000的PWM产生中断信号,在PWM中断服务程序中启动SPI读操作,因此ADC_BUSY信号线还可以省掉不用。为了提高SPI操作效率,SPI数据接收在SPI FIFO中断中完成,读取AD数据后直接存放在M4与A7(Linux)共享的乒乓buffer中。M4程序在采样到指定个数的AD数据后,通过RPmsg协议通知应用程序,应用程序根据RPmsg提供的信息从共享内存中读取AD数据。M4程序使用了FreeRTOS操作系统,主要的代码如下:


/*!
* PWM中断服务程序,在PWM中断中启动SPI读取上一次AD转换结果
*/
void ESM_PWM3_HANDLER(void) 
{
    uint8_t i;
    PWM_ClearStatusFlag(ESM_PWM3, pwmStatusCompare);
    /*每个数据包的第一次采样记录us定时器的值,用于时间同步*/
    if (samplingCnt == 0)
        data_packed.time_stamp = GPT_ReadCounter(ESM_GPT1);
/* 向SPI TX FIFO填数据即同时启动SPI读操作,读取4个DWORD、共128bit SPI数据 */
    for (i = 0; i < 4; i++)
    {
        ECSPI_TXDATA_REG(ESM_SPI1) = 0;
    }
    samplingCnt = (samplingCnt + 8) % sampling_len;
}
/*!
* SPI中断服务程序,为了提高SPI操作效率,当SPI FIFO中接收到超过32个DWORD数时产生中断
* 在中断服务程序中将SPI数据读出
*/
void ESM_SPI1_HANDLER(void)
{
    uint32_t tmp;
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    /* Disable all SPI interrupt */
    ECSPI_INTREG_REG(ESM_SPI1) = 0;
    while (ECSPI_STATREG_REG(ESM_SPI1) & ECSPI_STATREG_RR_MASK)
    {
        tmp = ECSPI_RXDATA_REG(ESM_SPI1);
        /* 将AD数据存放在M4与A7(Linux)的共享内存中 */
        *((uint16_t *)mem_addr + shared_buf_idx++) = (uint16_t)(tmp >> 16);
        *((uint16_t *)mem_addr + shared_buf_idx++) = (uint16_t)tmp;
        if (shared_buf_idx >= sampling_len)
        {
            /* 当采样到指定长度的AD数据后,对乒乓buffer进行切换,
            并将xDataReadySemaphore信号量设置为有效 */
            shared_buf_idx = 0;
            if (mem_addr == SHARED_MEMORY_BASE + SHARED_MEMORY_BLOCK0)
            {
                data_packed.flags = 0;
                mem_addr = SHARED_MEMORY_BASE + SHARED_MEMORY_BLOCK1;
            }
            else
            {
                data_packed.flags = 1;
                mem_addr = SHARED_MEMORY_BASE + SHARED_MEMORY_BLOCK0;
            }
            /* Unlock the task to process the event. */
            xSemaphoreGiveFromISR(xDataReadySemaphore, &xHigherPriorityTaskWoken);
            /* Perform a context switch to wake the higher priority task. */
            portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
        }
    }
    ECSPI_ClearStatusFlag(ESM_SPI1, ecspiFlagRxfifoDataRequest);
    ECSPI_SetIntCmd(ESM_SPI1, ecspiFlagRxfifoDataRequest, true);
}
static void DataReadyTask(void *pvParameters)
{
    int result;
    for (;;)
    {
        /* 等待信号量,任务被无超时阻塞 */
        xSemaphoreTake(xDataReadySemaphore, portMAX_DELAY);
        /* 通过RPmsg多核协议将当前数据包信息上报给应用程序 */
        result = RPMSG_Send(&data_packed, sizeof(data_packed));
        assert(result == 0);
    }
}


  ESM7000高速AD采集方案充分利用了i.MX7D的异构CPU架构,由高性能的Cortex-A7完成人机交互、数据处理、通讯管理等复杂运算,而实时的AD数据采集则由i.MX7D的Cortex-M4完成。我们基于此方案推出了ESM2001工控机,感兴趣的客户可参考这里:EMX2000系列工控机


  ADS8588S支持的最大采样率为200kSPS,本方案经过简单的硬件改造,不需要增加任何硬件成本,也可实现200kSPS的高速AD采集,有需要的客户可与英创联系。


  ESM7000异常CPU架构的实时应用介绍及软件开发说明请参考:

  ESM7000异构CPU架构的实时应用

  ESM7000 Cortex-M4技术开发参考手册