cancel
Showing results for 
Search instead for 
Did you mean: 

regarding storage of values in last two bytes in an array

RWagh.2
Associate II

Hello Folks,

I have connected my STML011G4U7 with ISO7816. In my code I am parsing ATR which is an 8 byte array and sending it. Here I need to measure the voltage from ADC which would be (3.3 V) and store it in the last two bytes of an array. How will I do that?

byte ATR[] = { 0x3B, 0x06, 0x55, 0x63, 0x63, 0x3D, 0x00, 0x00 };

I need to store the value coming from ADC in the last two bytes ADCH and ADCL. How will I do that?

19 REPLIES 19
RWagh.2
Associate II

Thanks for the info Peter. I did include the caibration start in my code and defined the VREFINT_CAL. now where i would be able to see the value of VREFINT_CAL

You do not have to display or see the value of VREFINT_CAL, but only use it for the calculation.

Did you read the section in RM0377? It says how to convert the ADC value to the measurement result.

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
RWagh.2
Associate II

Yes I did check.

The following formula gives the actual VDDA voltage supplying the device:

VDDA = VDDA_Charac x VREFINT_CAL / VREFINT_DATA

In my case VDDA_Charac = 3 volt , VREFINT_DATA the raw value i am getting is 1024. How will I figure out the VREFINT_CAL?

Peter BENSCH
ST Employee

You have already defined VREFINT_CAL, so you only have to insert it into your programme. The only constant is VDDA_Charac with the value 3V, VREFINT_DATA is a variable and VREFINT_CAL is an address from which the value is fetched by the programme.

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
RWagh.2
Associate II

Hi Peter. I have tried to put that in my code but it's giving syntax error

 void ReadVCC(byte ATR[])

 {

 HAL_ADCEx_Calibration_Start(&hadc, ADC_SINGLE_ENDED);

 HAL_ADC_Start_IT(&hadc);

 HAL_ADC_PollForConversion(&hadc, HAL_MAX_DELAY);

 adcval = HAL_ADC_GetValue(&hadc);

 VDDA = 3.3 * (VREFINT_CAL / adcval);

 ATR[6] = (uint8_t) (adcval>>8); // MSB

 ATR[7] = (uint8_t) (adcval & 0x00FF); // LSB

 HAL_ADC_Stop(&hadc);

 }

RWagh.2
Associate II

Error : ../Core/Src/main.c:121:30: error: invalid operands to binary / (have 'uint16_t *' {aka 'short unsigned int *'} and 'int')

These are the macros :

typedef unsigned char byte;

byte ATR[] = { 0x3B, 0x06, 0x55, 0x63, 0x63, 0x3D, 0x00, 0x00 };

uint16_t adcval;

uint32_t VDDA;

#define VREFINT_CAL_ADDR        0x1FF80078 /* datasheet p. 19 */

#define VREFINT_CAL ((uint16_t*) VREFINT_CAL_ADDR

Peter BENSCH
ST Employee

Have you ever made measurements with the ADC?

Do you know the firmware library, e.g. Projects\NUCLEO-L011K4\Examples\ADC, which contains many examples of how to use the different peripheral units?

  • The ADC can either trigger interrupts when it is ready, or be polled. Mixing both is not a good idea.
  • VDDA_Charac does not have the value 3.3 for the STM32L011, but 3.0.
  • VREFINT_CAL is a pointer, not a value.
  • Nevertheless, integer values should not be multiplied by a float like 3.0. It makes sense to introduce a factor of 1000 and use the value 3000 for VDDA_Charac instead of 3.0 and interprete the result as millivolts.
  • If you want to insert the calculated measured value of VDDA into your array, you should also take this calculated measured value and not the ADC value with which you measured the internal reference.

Regards

/Peter

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

Hi Peter, This is the first time I am writing a code. it would be good if you guide me how to get a rawadc val as I am getting just 1 Idk why.

also Do I need to select the VREFINT_channel as well along with the ADC pin?

RWagh.2
Associate II
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2022 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
 
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
 
 
/* USER CODE END Includes */
 
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
 
/* USER CODE END PTD */
 
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
 
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
 
/* USER CODE END PM */
 
/* Private variables ---------------------------------------------------------*/
ADC_HandleTypeDef hadc;
 
UART_HandleTypeDef huart2;
 
/* USER CODE BEGIN PV */
 
/* USER CODE END PV */
 
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ADC_Init(void);
static void MX_USART2_UART_Init(void);
/* USER CODE BEGIN PFP */
 
/* USER CODE END PFP */
 
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
 
/* USER CODE END 0 */
 
/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
 
	typedef unsigned char byte;
	byte ATR[] = { 0x3B, 0x06, 0x55, 0x63, 0x63, 0x3D, 0x00, 0x00 };
	uint16_t adcval;
	uint16_t VDDA;
 
	#define VREFINT_CAL_ADDR    0x1FF80078      // datasheet p. 19
    #define VREF 3000                           // voltage reference 3V
	uint16_t vrefint_cal;                       // VREFINT calibration value
	vrefint_cal = *((uint16_t*) VREFINT_CAL_ADDR); // read VREFINT_CAL_ADDR memory location
 
 
 
  /* USER CODE END 1 */
 
  /* MCU Configuration--------------------------------------------------------*/
 
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* USER CODE BEGIN Init */
 
  /* USER CODE END Init */
 
  /* Configure the system clock */
  SystemClock_Config();
 
  /* USER CODE BEGIN SysInit */
 
  /* USER CODE END SysInit */
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_ADC_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */
  void ISO7816_SendATR(void)
  {
      HAL_UART_Transmit(&huart2, (byte*)ATR, sizeof(ATR), 20);
      __HAL_UART_CLEAR_FEFLAG(&huart2);
      __HAL_UART_CLEAR_OREFLAG(&huart2);
 
      byte Dummy;
      while (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_RXNE))
          HAL_UART_Receive(&huart2, &Dummy, 1, 1);
  }
 
  void ADC_Calibration(void)
  {
	  if (HAL_ADCEx_Calibration_Start(&hadc, ADC_SINGLE_ENDED) != HAL_OK)
	  {
	    /* Calibration Error */
	    Error_Handler();
	  }
  }
 
  void ReadVCC(byte ATR[])
  {
 
	  HAL_ADC_Start_IT(&hadc);
	  HAL_ADC_PollForConversion(&hadc, HAL_MAX_DELAY);
	  adcval = HAL_ADC_GetValue(&hadc);
	  VDDA = VREF * (vrefint_cal / adcval);
	  ATR[6] = (uint8_t) (VDDA>>8); // MSB
	  ATR[7] = (uint8_t) (VDDA & 0x00FF); // LSB
 
  }
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
	  ADC_Calibration();
	  ISO7816_SendATR();
 
	  ReadVCC(ATR);
	  HAL_ADC_Stop(&hadc);
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
 
/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
 
  /** Configure the main internal regulator output voltage
  */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
 
  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
  RCC_OscInitStruct.MSIState = RCC_MSI_ON;
  RCC_OscInitStruct.MSICalibrationValue = 0;
  RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_5;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
 
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
 
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART2;
  PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
}
 
/**
  * @brief ADC Initialization Function
  * @param None
  * @retval None
  */
static void MX_ADC_Init(void)
{
 
  /* USER CODE BEGIN ADC_Init 0 */
 
  /* USER CODE END ADC_Init 0 */
 
  ADC_ChannelConfTypeDef sConfig = {0};
 
  /* USER CODE BEGIN ADC_Init 1 */
 
  /* USER CODE END ADC_Init 1 */
 
  /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
  */
  hadc.Instance = ADC1;
  hadc.Init.OversamplingMode = DISABLE;
  hadc.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV1;
  hadc.Init.Resolution = ADC_RESOLUTION_12B;
  hadc.Init.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
  hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
  hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc.Init.ContinuousConvMode = DISABLE;
  hadc.Init.DiscontinuousConvMode = DISABLE;
  hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc.Init.DMAContinuousRequests = DISABLE;
  hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  hadc.Init.LowPowerAutoWait = DISABLE;
  hadc.Init.LowPowerFrequencyMode = ENABLE;
  hadc.Init.LowPowerAutoPowerOff = DISABLE;
  if (HAL_ADC_Init(&hadc) != HAL_OK)
  {
    Error_Handler();
  }
 
  /** Configure for the selected ADC regular channel to be converted.
  */
  sConfig.Channel = ADC_CHANNEL_8;
  sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
  if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ADC_Init 2 */
 
  /* USER CODE END ADC_Init 2 */
 
}
 
/**
  * @brief USART2 Initialization Function
  * @param None
  * @retval None
  */
static void MX_USART2_UART_Init(void)
{
 
  /* USER CODE BEGIN USART2_Init 0 */
 
  /* USER CODE END USART2_Init 0 */
 
  /* USER CODE BEGIN USART2_Init 1 */
 
  /* USER CODE END USART2_Init 1 */
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 13441;
  huart2.Init.WordLength = UART_WORDLENGTH_9B;
  huart2.Init.StopBits = UART_STOPBITS_2;
  huart2.Init.Parity = UART_PARITY_EVEN;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  if (HAL_HalfDuplex_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART2_Init 2 */
 
  /* USER CODE END USART2_Init 2 */
 
}
 
/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
 
  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
 
}
 
/* USER CODE BEGIN 4 */
 
/* USER CODE END 4 */
 
/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}
 
#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

Hi Peter. Kindly check my code and let me know in case of any corrections

Huh? Rather:

# define VREFINT_CAL (*(uint16_t *)0x1FF80078)

:)

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice