Hello everyone.
I know, this topic has already been mentioned here, but no working solution was found so far.
Brief summary: The Portenta H7 has an advertized ADC sampling rate of 3.6 Msps. However, timing the analogRead() function results in a sobering 20 kHz rate, i.e. one ADC read takes about 50 us.
The solution is to include DMA in the ADC process. I found one site, which explains it well for the STM32 (even with a video on YouTube):
Two examples are provided. The first shows a single ADC reading, the second introduces DMA. As a start, I wanted to test the single ADC read, because the DMA example is based on it.
The code can be found on the site, however, the HAL code and the Init() code is missing. Therefore I opened CubeMX for the STM32H743 Nucleo (since the Portenta H7cannot be included into CubeMX) and assigned the ADC1 as shown in the digikey Video.
I compared the generated code with another ADC DMA Stm32 example:
and found that its nearly equal. Now the Arduino code:
#include "stm32h7xx_hal_gpio.h"
#include "stm32h7xx_hal.h"
#include "stm32h7xx_hal_adc.h"
int RxPin = 0;
int ADC_raw = 0;
const int TxPin = 0;
uint16_t raw = 0;
ADC_HandleTypeDef hadc1;
void setup() {
// put your setup code here, to run once:
MX_GPIO_H15_Init(); // Initialize GPIO-H for VLC
MX_adc1_Init(); // Initialize ADC1
Serial.begin(115200);
//analogReadResolution(16);
pinMode(RxPin, INPUT);
pinMode(TxPin, OUTPUT);
}
void loop() {
delay(500);
// Test:
HAL_GPIO_WritePin(GPIOH, GPIO_PIN_15, GPIO_PIN_SET); // SET Pin PH15 HIGH
delay(1);
HAL_GPIO_WritePin(GPIOH, GPIO_PIN_15, GPIO_PIN_RESET); // SET Pin PH15 LOW
delay(1);
HAL_GPIO_WritePin(GPIOH, GPIO_PIN_15, GPIO_PIN_SET); // SET Pin PH15 HIGH
HAL_ADC_Start(&hadc1); // Get ADC value
HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY); //wait until ADC conversion completes.... this is where the code hangs, see oscilloscope pic
raw = HAL_ADC_GetValue(&hadc1);
HAL_GPIO_WritePin(GPIOH, GPIO_PIN_15, GPIO_PIN_RESET); // SET Pin PH15 LOW
Serial.print(raw);
delay(1);
}
static void MX_adc1_Init(void)
{
ADC_ChannelConfTypeDef sConfig = {0};
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
hadc1.Init.Resolution = ADC_RESOLUTION_16B;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE; //also possible: ADC_SCAN_ENABLE;
hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;
hadc1.Init.LowPowerAutoWait = DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR;
hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
hadc1.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;
hadc1.Init.OversamplingMode = DISABLE;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
// __HAL_RCC_ADC1_CLK_ENABLE(); // necessary? -> found in https://www.st.com/resource/en/user_manual/um1905-description-of-stm32f7-hal-and-lowlayer-drivers-stmicroelectronics.pdf
sConfig.Channel = ADC_CHANNEL_1; // 'Maybe this is the problem? Which channel should I choose for Pin A0 on the arduino portenta?'
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
}
// -------------------------------- GPIO Pin "PH15" Initialization for STM32 ---------------------------------
void MX_GPIO_H15_Init()
{
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOH_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct;
/*Configure GPIO pin : PH15 */
GPIO_InitStruct.Pin = GPIO_PIN_15; // Pin15
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // digital Output, push-pull configuration
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
HAL_GPIO_Init(GPIOH, &GPIO_InitStruct); // GPIO-H
}
// ----------------------------------------------------------------------------------------------------------
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
/* USER CODE END Error_Handler_Debug */
}
What it does, is setting pin PH15 high, low, high and then start one AD read and wait until it is finished. Only then, PH15 is set low again. Unfortunately, HAL_ADC_PollForConversion() is where the code hangs and waits, as can be seen in the oscilloscope picture provided in the comments.
The reason might be that adc1_Init() was not adapted to the Portenta H7 and that some settings are incorrect, because it is not included in CubeMX.
Does anyone get along with the settings in adc1_Init()? If we could make this example work, the next step would be to include DMA....
Thank You!