使用:
我正在开展一个 DIY 示波器项目,我想尝试尽可能提高 STM32F7 系列 ADC 的速度和精度。我正在阅读有关该主题的文献并不断获得见解,我逐渐了解到,使用 DMA 管道是一种有效的数据流传输方式,且不会导致 CPU 陷入困境。我能够成功地用相对准确的 12 位 ADC 值填充缓冲区,并且在调试时可以看到它们被填充到 DMA 寄存器中。当我尝试将 adc_buf 数组传输到我设备的板载 uart 端口 huart3 时,出现了问题。
我已经验证了uart3口可以传输buffer。我发送了一个字符数组,
char msg[] = "\n\rThe cow jumped over the moon\r\n";
与 HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), 0xFFFF);
。请参阅下面的输出,了解腻子窗口上的结果。我还尝试使用 for 循环来使用 snprintf 并分配另一个缓冲区来传输,但这既不起作用也不符合项目的目标。我猜 for 循环不是最有效的方法。我看到其他答案表明初始化 DMA 和 UART 的顺序很重要,但最新的 CubeMX 更新似乎已经解决了这个问题。这不是问题。
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USART3_UART_Init();
MX_ADC1_Init();
MX_ETH_Init();
MX_USB_OTG_FS_PCD_Init();
简单来说,我的工作流程是这样的:
/* USER CODE BEGIN PD */
#define ADC_BUF_LEN 8
/* USER CODE END PD */
/* USER CODE BEGIN PV */
uint16_t adc_buf[ADC_BUF_LEN];
/* USER CODE END PV */
int main(void)
{
/* USER CODE BEGIN 1 */
char msg[] = "\n\rThe cow jumped over the moon\r\n";
char buffer[50];
/* USER CODE END 1 */
//...Inits
/* USER CODE BEGIN 2 */
HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), 0xFFFF); // transmits cow message fine
HAL_ADC_Start_DMA(&hadc1, (uint32_t *) &adc_buf, ADC_BUF_LEN);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1) {
// wait for huart3 instance to write?
while (READ_BIT(huart3.Instance->ISR, USART_ISR_TC)==0){asm("nop");}
HAL_UART_Transmit_DMA(&huart3, (uint8_t*)adc_buf, ADC_BUF_LEN * sizeof(uint8_t));
// Must start ADC->DMA process again or values don't seem to be read continuously
HAL_ADC_Start_DMA(&hadc1, (uint32_t *) &adc_buf, ADC_BUF_LEN);
}
/* USER CODE END WHILE */
}
我希望我的结果看起来像这样:
The cow jumped over the moon
4095
4095
4095
4092
等等。但我得到的却是垃圾:
/
The cow jumped over the moon
▒;▒▒Z*▒S=▒Z*▒S=▒P▒▒=KR2▒]▒▒RgG7▒]▒▒RgG7▒
▒▒
}▒:▒▒
▒▒▒4▒▒
▒▒▒4▒▒▒▒▒▒1▒▒▒▒
▒1▒▒▒▒
再往下,我尝试编写一些中断,它们似乎触发得很好。
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef *hadc) {
HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);
}
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) {
HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);
当我在这里设置断点时,这些中断似乎运行正常。我已经在 usart3 外设上设置了全局中断,并确保 DMA、usart3 和 ADC1 设置为正常而不是循环。 DMA 和 USART 似乎独立运行良好,只是不能一起运行。
感谢您的宝贵时间。
HAL_UART_Transmit_DMA(&huart3, (uint8_t*)adc_buf ...
它不会打印 ADC 读数的 ASCII 表示形式。您需要将uint16_t
数字转换为字符串,然后传输该字符串。该转换必须与 ADC DMA 同步。
检测 DMA 事务结束并不容易。 TC 标志并不意味着 DMA 事务已完成。您需要检查 DMA 标志,然后检查 TC。然后你就可以忍受另一个转变了。