This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
工具与软件:
您好(Jagadish)、
我一直在按照 span227的指示实施具有 DMA 的 ADC。 我需要从特定(单)通道获取20个样本并将其存储到 RAM 中。 为了简化操作、我首先通过单个样本触发 DMA 请求。
// // Inside void main() // adcInit(); adcREG1->ADG1CHNSELMODECTRL = 0x0A; // enable enhanced channel selection mode for group1 adcREG1->ADG1MAXCOUNT = 1; // 1 conversion total adcREG1->ADG1CURRCOUNT = 0; // clear group1 current_count counter adcREG1->G1DMACR = 0x09; // DMA request on group1 conversion end adcEnableNotification(adcREG1, adcGROUP1);
// // Inside void main() // dmaEnable(); dmaReqAssign(1, 10); dmaConfigCtrlPacket( ADG1_ptr, // control packet for group1 (uint32)(&adcREG1->GxBUF[1]), // group1 results FIFO (uint32)(&adc1_G1_results), // group1 results in CPU data RAM 1, // number of frames to be transferred 1, // number of elements per frame 0, // next channel to be chained, 0 = disable chaining 2, // read element size (32 bits) 2, // write element size (32 bits) 1, // transfer type = 1 ==> block transfer 0, // read addressing mode = 0 ==> fixed 1, // write addressing mode = 1 ==> post-incremented 1, // autoinit enabled 0, // read address element index offset = 0 0, // write address element index offset = 0 0, // read address frame index offset = 0 0 // write address frame index offset = 0 ); dmaSetCtrlPacket(DMA_CH1, *ADG1_ptr); dmaEnableInterrupt(DMA_CH1, BTC); dmaSetChEnable(DMA_CH1, DMA_HW);
并在具有足够堆栈分配的任务中打印结果:
// // Inside task // while (1) { adcStartConversion(adcREG1, adcGROUP1); printf("ADC: %u\n", adc1_G1_results[0]); vTaskDelay(xDelay); }
在处理 每帧不同数量的元素(1、5、20)后、我能够通过调试器看到 DMA 引擎将请求的计数转移到目标 RAM 缓冲区中。 我不使用连续转换-在 以下主题中读取 Sunil Oak 的响应后: e2e.ti.com/.../tms570lc4357-dma-with-adc-in-continuous-mode
遗憾的是、在不改变照明水平的情况下、我从 Launchpad 套件通道6上的光电晶体管得到了非常奇怪的结果。 我知道它会打印整个 uint32 、包括标志和通道 ID、但读数差异仍然很大(在单个恒定通道的上下文中)。 其内容如下所示:
ADC: 0 ADC: 68347 ADC: 68347 ADC: 68347 ADC: 68348 ADC: 2812 ADC: 2811 ADC: 68347 ADC: 2812 ADC: 2811
我也很难理解以下内容:
1. ADC 和 DMA 中断通知都不会被触发。 我不仅尝试使用 HALCoGen 功能(如上述代码片段中所示)、还通过在 INT 使能寄存器中分配适当的位字段值进行了尝试。
void dmaGroupANotification(dmaInterrupt_t inttype, uint32 channel) { sciSendByte(scilinREG, 'D'); return; } void adcNotification(adcBASE_t *adc, uint32 group) { sciSendByte(scilinREG, 'A'); return; }
我的 GIO 和 SCI 中断(FIQ/IRQ)能够正常工作(在 FreeRTOS 环境中)。
2. API 中提及的 ADC 存储对象与 TRM 之间的关系是什么:
3.基于上述情况, DMA 传输应该考虑哪些因素? 如何配置 ADC FIFO 以实现最佳的 DMA 传输效率?
我希望我的帖子不是那么压倒性,但我真的花了大约一个星期的研究,我是无处可去。
非常感谢使用任何其它最新的示例代码。。。
感谢您的理解和诚挚的问候、
Varban
您好、Varban、
我的建议是尝试在 ADC DMA 中使用以下重点方法。
您每次正确地需要20个样本、所以将块大小配置为 20个、这样 DMA 将在20次转换后获得 ADC 触发。 一旦 DMA 从 ADC 获得触发信号、我们应配置 DMA、使其元素数量为1、帧数为20、一旦我们执行此操作、DMA 将把所有这20个转换结果从 ADC 存储器传输到 RAM。 一旦 DMA 完成20个转换结果的传输、它将触发您一个块传输完成中断。
一旦您获得 DMA 块传输中断、您就可以在由 DMA 移位的 RAM 中对 ADC 数据执行所需的操作。
我没有任何直接的例子、但我会尝试在您的终端上实现、如果您在实现过程中遇到任何困难、我会尝试进一步为您提供帮助。
——
谢谢、此致、
Jagadish。
已编辑
尊敬的 Jagadish:
感谢您的指导、并对我的延迟响应表示抱歉。
以上就是我对建议方法的理解。 基于以下 HALCoGen 配置:
我写了以下内容:
xTaskHandle xUserTaskHandle; void vUserTask(void *pvParameters) { const TickType_t xDelay = 500 / portTICK_PERIOD_MS; uint16_t n = 0; while (1) { adcStartConversion(adcREG1, adcGROUP1); for (n = 0; n < ADC_SAMPLE_COUNT; n++) { printf("[%u] Ch: %u, ADC: %u\n", n, (uint32)((adc1_G1_results[n] >> 16U) & 0x1FU), // Channel ID (uint16)(adc1_G1_results[n] & 0xFFFU)); // Value } printf("----------------\n"); vTaskDelay(xDelay); } } /* USER CODE END */ void main(void) { /* USER CODE BEGIN (3) */ gioInit(); hetInit(); esmInit(); sciInit(); sciEnableNotification(scilinREG, SCI_RX_INT); sciReceive(scilinREG, 1, &rx_byte); adcInit(); adcREG1->G1DMACR = (1U << 0U) | // G1_DMA_EN - ADC module generates a DMA transfer when the ADC has written to the Group1 memory. G1_BLK_XFER bit must be cleared to ‘0’ for this DMA request to be generated. (1U << 2U) | // G1_BLK_XFER - ADC module generates a DMA request when the ADC has written G1_BLOCKS number of buffers into the Group1 memory. (1U << 3U) | // DMA_G1_END - ADC module generates a DMA request when the ADC has completed the conversions for all channels selected for conversion in the group1. (ADC_SAMPLE_COUNT << 16U); // G1_BLOCKS - One DMA request is generated if the G1_BLK_XFER is set to ‘1’ and the specified number of Group1 conversion results have been accumulated // ADC_SAMPLE_COUNT = 32U, equal to the configured FIFO size inside HALCoGen // adcEnableNotification(adcREG1, adcGROUP1); dmaEnable(); dmaReqAssign(1, 10); dmaConfigCtrlPacket(ADG1_ptr, // control packet for group1 (uint32)(&adcREG1->GxBUF[1]), // group1 results FIFO (uint32)(&adc1_G1_results), // group1 results in CPU data RAM ADC_SAMPLE_COUNT, // number of frames to be transferred 1, // number of elements per frame 0, // next channel to be chained, 0 = disable chaining 2, // read element size (32 bits) 2, // write element size (32 bits) 1, // transfer type = 1 ==> block transfer 0, // read addressing mode = 0 ==> fixed 1, // write addressing mode = 1 ==> post-incremented 1, // autoinit enabled 0, // read address element index offset = 0 0, // write address element index offset = 0 0, // read address frame index offset = 0 0); // write address frame index offset = 0 dmaSetCtrlPacket(DMA_CH1, *ADG1_ptr); dmaSetChEnable(DMA_CH1, DMA_HW); // dmaEnableInterrupt(DMA_CH1, BTC); if(xTaskCreate(vUserTask, "UserTask", 512, NULL, tskIDLE_PRIORITY + 1, &xUserTaskHandle) != pdTRUE) { while (1); } _enable_IRQ(); _enable_FIQ(); vTaskStartScheduler(); return; /* USER CODE END */ }
和 ADC DMA 配置寄存器的"缩放":
#define ADC_SAMPLE_COUNT 32U // Equal to the configured FIFO size in HALCoGen ... adcREG1->G1DMACR = (1U << 0U) | // G1_DMA_EN - ADC module generates a DMA transfer when the ADC has written to the Group1 memory. G1_BLK_XFER bit must be cleared to ‘0’ for this DMA request to be generated. (1U << 2U) | // G1_BLK_XFER - ADC module generates a DMA request when the ADC has written G1_BLOCKS number of buffers into the Group1 memory. (1U << 3U) | // DMA_G1_END - ADC module generates a DMA request when the ADC has completed the conversions for all channels selected for conversion in the group1. (ADC_SAMPLE_COUNT << 16U); // G1_BLOCKS - One DMA request is generated if the G1_BLK_XFER is set to ‘1’ and the specified number of Group1 conversion results have been accumulated // ADC_SAMPLE_COUNT = 32U, equal to the configured FIFO size inside HALCoGen
尽管我最后遇到了 DMA 传输、但我仍然有以下问题和观察结果。
1.缓冲区内容
在我最初的错误之后、在循环中使用硬编码索引0进行了编辑(抱歉、混淆了)。
结果如下:仅对一个值进行采样、缓冲器中的所有其他值都是0。
---------------- [0] Ch: 6, ADC: 420 [1] Ch: 8, ADC: 0 [2] Ch: 8, ADC: 0 [3] Ch: 8, ADC: 0 [4] Ch: 8, ADC: 0 [5] Ch: 8, ADC: 0 [6] Ch: 8, ADC: 0 [7] Ch: 8, ADC: 0 [8] Ch: 8, ADC: 0 [9] Ch: 8, ADC: 0 [10] Ch: 8, ADC: 0 [11] Ch: 8, ADC: 0 [12] Ch: 8, ADC: 0 [13] Ch: 8, ADC: 0 [14] Ch: 8, ADC: 0 [15] Ch: 8, ADC: 0 [16] Ch: 8, ADC: 0 [17] Ch: 8, ADC: 0 [18] Ch: 8, ADC: 0 [19] Ch: 8, ADC: 0 [20] Ch: 8, ADC: 0 [21] Ch: 8, ADC: 0 [22] Ch: 8, ADC: 0 [23] Ch: 8, ADC: 0 [24] Ch: 8, ADC: 0 [25] Ch: 8, ADC: 0 [26] Ch: 8, ADC: 0 [27] Ch: 8, ADC: 0 [28] Ch: 8, ADC: 0 [29] Ch: 8, ADC: 0 [30] Ch: 8, ADC: 0 [31] Ch: 8, ADC: 0 ----------------
我还尝试了 adcResetFiFo()在 adcStartConversion()之前和之后-行为(缓冲区内容)是完全相同的。
2. G1_Blocks 的值
我注意到 adcStartConversion()将 G1_Blocks 从32U 更改为31U。 然后、寄存器"自动"恢复到32U:
这是否正常?
3. G1_DMA_EN 位
当 G1_DMA_EN 位为0或1时、我在程序行为上没有观察到任何差异。 此场景的推荐配置应该是什么?
谢谢。此致、
Varban
您好!
我最终通过激活 adcREG1、adcGROUP1中的所有通道并将 FIFO 大小设置为等于通道数量(在本例中为- 24)来运行 DMA。
然后,在 非连续模式下调用 adcStartConversion()后, ADC 一次性获取 FIFO 中的所有通道读数,并向 RAM 触发一个 DMA -传输所有24个 uint32_t 值。
这看起来我最初要寻找的(读取单个通道 N 次、填充队列并在 FIFO 满事件时触发 DMA)根据设计是不可能的、如果我错了、请纠正。
谢谢。此致、
Varban
您好、Varban、
您能否参考以下示例配置和代码:
e2e.ti.com/.../ADC_5F00_with_5F00_DMA_5F00_RM46.zip
在上面的工程中、我能够使用 DMA 将通道6的20个样本成功传输到另一个 RAM 缓冲区。
我认为与您项目的主要区别在于、我在这里启用了连续转换模式、而不是单次转换模式。
我启用此功能是因为如果不启用这种连续转换模式、每当我们发出开始转换命令时、通道6数据始终存储在 ADC RAM 存储器的单个位置。
我想这只是预期、我的意思是单次模式只会对所有已启用的通道执行一次转换、并会将数据存储在 ADC RAM 中。 如果我们启用第6个通道、则每次仅在 RAM 的第一个位置存储其数据。
——
谢谢、此致、
Jagadish。
尊敬的 Jagadish:
感谢您的答复!
我在连续模式下的观察结果是完全相同的。
然而、仍然不建议将 DMA 与 连续 模式一起使用、如 Sunil Oak 在本主题中所述: e2e.ti.com/.../tms570lc4357-dma-with-adc-in-continuous-mode?
此致、
Varban
您好、Varban、
[报价 userid="208956" url="~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1443070/tms570ls1224-adc-with-dma-spna227/5545796 #5545796"]然而、是否仍然不建议将 DMA 与 连续 模式配合使用、正如 Sunil Oak 在本主题中所说的那样: e2e.ti.com/.../tms570lc4357-dma-with-adc-in-continuous-mode?我 认为这是正确的。
即使您也验证我的转换结果、您也可以看到、对于最后4次转换、已设置空标志:
正如他们所说的、 在连续模式与 DMA 之间似乎存在一些时序问题。
此外、当我们为此转换模式选择单通道时、转换将很快发生。
正如您看到的、一个通道的转换时间仅为1.6us、这意味着我们将以每1.6uS 速率获取样本。 我想我们不需要具有如此低间隔的样本。
因此、他们倾向于使用计时器或 PWM 来生成样片。
——
谢谢、此致、
Jagadish。
您可以看到一个通道的转换时间仅为1.6us、这意味着我们将每1.6uS 获取一次样片。 我想我们不需要具有如此低间隔的样本。[/报价]从我所观察到的情况来看、在 DMA 情况下、可能需要一些基于中断的状态机(以指示新的传输完成)、而中断(即使具有非常简单和快速的处理)也可能会使 RTOS 流受阻。
也许你是对的、但我从未在 RTOS 环境中测试过 DMA。