Showing results for 
Search instead for 
Did you mean: 

Feedback Requested on general approached used for ADC

Associate III

Hello, reaching out to see if anyone can provide some thoughts on a project I'm working on.  The project works but though I'm a longtime Arduino developer this is my first STM32 project - so not 100% sure of some of the parameters I've chosen are the best or most efficient.


The project is simple, custom board implementing a remote control that will eventually transmit using BLE.  The remote control design is straightforward and similar to a XBox style controller.  It has two joysticks, two toggle switches, two potentiometers (dials), four push buttons and a battery monitor (voltage divider).  Here is an image from my HW design software if that helps:


All of the circuitry works except RF, which I haven't tested yet, and I've written the code in STM32CubeIDE to read the inputs.  Here are the specifics along with something I'm not sure about:

  • It uses a timer set to read all of those at once every 200ms - which is probably around the granularity i'm looking for.
  • The device it will control really just needs 8-bit data.  Currently I have the ADC resolution set to 12-bit and I map that to a range of 0-255 but I've also experimented with just using 8-bit resolution in the ADC (which would eliminate the need to map).  I only went higher because I'm looking at how best to read and store the voltage.  
  • When the timer fires I just read the 7 analog values and put into a struct.  I also read the digital values at the same time as it seemed like a good place to do it without using another timer or wait loop.  Not sure if that adds issues being done in the callback.
  • The only issue I seem to have is that my joysticks X and Y are way too sensitive.  No matter what resolution I pick (or other setting I play with) they reach full value with minor joystick movement.  Same brand I used with Arduino and I don't recall seeing that there but this is custom hardware and STM32 so not sure any of the other settings could be causing that (or if they're just crappy joysticks)


  1. Is there a pro/con with different ADC resolutions (i.e. is it more efficient and/or less overhead on the processor to do one vs. the other if I have a choice)
  2. I'm not sure what to set the sampling time to - or really what that does.  It's currently at 247.5 cycles but I didn't really see a difference when it was at 2.5 cycles. Should this be higher or lower, etc - especially since I'm reading the digital values in the ADC_ConvCpltCallback method

Coming from the Arduino world all of the ADC conversion stuff is new to me, so learning it as I go.  There are a lot of options to choose (trigger conversion edge, sampling time, offset number, overrun behaviour, end of sequence selection, etc.) and it's hard to tell from the documentation what they do and how they all work together.  This all works so I'm really curious if someone with more experience has any ideas on if it could be better, more efficient, etc.  

Here is my ADC setup


There isn't a lot of custom code, most is IDE generated HAL stuff, so below are the relevant sections




void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {

	// Continuous ADC conversion of Analog inputs is complete and stored in the data structure to be used later.
	data.j1PotX = (uint8_t) MAP(AD_RES_BUFFER[0], 0, 4096, 0, 256);
	data.j1PotY= (uint8_t) MAP(AD_RES_BUFFER[1], 0, 4096, 0, 256);
	data.j2PotX = (uint8_t) MAP(AD_RES_BUFFER[2], 0, 4096, 0, 256);
	data.j2PotY = (uint8_t) MAP(AD_RES_BUFFER[3], 0, 4096, 0, 256);
	data.pot1 = (uint8_t) MAP(AD_RES_BUFFER[4], 0, 4096, 0, 256);
	data.pot2 = (uint8_t) MAP(AD_RES_BUFFER[5], 0, 4096, 0, 256);
	data.BatteryVoltage = AD_RES_BUFFER[6];

	// For convenience, read digital pins here
	data.j1Button = HAL_GPIO_ReadPin(j1Button_GPIO_Port, j1Button_Pin);
	data.j2Button = HAL_GPIO_ReadPin(j2Button_GPIO_Port, j2Button_Pin);
	data.tSwitch1 = HAL_GPIO_ReadPin(tSwitch1_GPIO_Port, tSwitch1_Pin);
	data.tSwitch2 = HAL_GPIO_ReadPin(tSwitch2_GPIO_Port, tSwitch2_Pin);
	data.button1 = HAL_GPIO_ReadPin(Button1_GPIO_Port, Button1_Pin);
	data.button2 = HAL_GPIO_ReadPin(Button2_GPIO_Port, Button2_Pin);
	data.button3 = HAL_GPIO_ReadPin(Button3_GPIO_Port, Button3_Pin);
	data.button4 = HAL_GPIO_ReadPin(Button4_BOOT0_GPIO_Port, Button4_BOOT0_Pin);

	HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);


uint16_t MAP(uint16_t au16_IN, uint16_t au16_INmin, uint16_t au16_INmax, uint16_t au16_OUTmin, uint16_t au16_OUTmax)
    return ((((au16_IN - au16_INmin)*(au16_OUTmax - au16_OUTmin))/(au16_INmax - au16_INmin)) + au16_OUTmin);





Here is main, just some extra initialization and then printing out to the USB for now




int main(void)

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  /* Config code for STM32_WPAN (HSE Tuning must be done before system clock configuration) */

  /* USER CODE BEGIN Init */
  //LL_HSEM_1StepLock( HSEM, 5 );  // CES:  Forum has this as a fix for USB+BLE

  /* Configure the system clock */

/* Configure the peripherals common clocks */

  /* IPCC initialisation */

  /* Initialize all configured peripherals */

  HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);
  // Turn on Blue LED, indicating that we're NOT in boot mode and all initializations are complete
  HAL_ADC_Start_DMA(&hadc1, (uint32_t *) AD_RES_BUFFER, 7);

  /* Init code for STM32_WPAN */

  /* Infinite loop */

  while (1)
	  // Read a value then delay for 1 second
	  //HAL_GPIO_ReadPin(GPIOx, GPIO_Pin)
	  //data.tSwitch1 = HAL_GPIO_ReadPin(tSwitch1_GPIO_Port, tSwitch1_Pin);
	  //data.j1PotX = analogRead(&hadc1, J1POTX_ADC_CHANNEL);
	  //data.j1PotY = analogRead(&hadc1, J1POTY_ADC_CHANNEL);
	  //data.j2PotY = analogRead(&hadc1, J2POTY_ADC_CHANNEL);
	  bufLen = snprintf(txBuf, 256,
			  "J1PotX: %u\t"
			  "J1PotY: %u\t"
			  "J1Button: %u\t"
			  "J2PotX: %u\t"
			  "J2PotY: %u\t"
			  "J2Button: %u\t"
			  "pot1: %u\t"
			  "pot2: %u\t"
			  "Button1: %u\t"
			  "Button2: %u\t"
			  "Button3: %u\t"
			  "Button4: %u\t"
			  "Battery: %u\r\n",
			  data.j1PotX, data.j1PotY, data.j1Button, data.j2PotX, data.j2PotY, data.j2Button, data.pot1, data.pot2,
			  data.button1, data.button2, data.button3, data.button4, data.BatteryVoltage);
	  CDC_Transmit_FS((uint8_t *) txBuf, bufLen);