2023-12-12 08:43 AM
Hello all,
I have done my due diligence looking everywhere for an answer to this as well as trying many different variations of the code I will post below. My issue is my LCD will not display the ADC value from a trimpot any other way. I thought at first maybe I was not giving the ADC_ON enough clock cycles as per the rm. So I added 1, 2, 3, all the way to like 16 asm("NOP") commands and I tried rearranging all manner of things in the offending portion. The ONLY solution I could figure out was using the following twice:
ADC1-> CR2 |= ADC_CR2_CAL;
ADC1-> CR2 |= ADC_CR2_CAL;
-or, similarly-
ONCE in the multiple bitwise operation and ONCE a few lines below:
// ENSURE ADC IS ON for CAL for 2cycles!
ADC1 -> CR2 |= (ADC_CR2_ADON | ADC_CR2_CONT | ADC_CR2_CAL); //this is = 1 cycle
//wait for ADC to turn on!
while((ADC1-> CR2 & ADC_CR2_ADON) == 0){} //this is = 2 cycles!
//It should be on by now
ADC1-> CR2 |= ADC_CR2_CAL;
FULL CODE:
#include "main.h"
#include "LCDFunctions.h"
void SystemClock_Config(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
InitializePortsForLCD();
InitializeTheLCDDisplayAndModes();
// Enable the ADC Clock Interface
RCC-> APB2ENR |= RCC_APB2ENR_ADC1EN;
//Turn on the HighSpeedInternal 8Mhz clock
RCC-> CR |= RCC_CR_HSION;
//wait for the clock to turn on
while((RCC->CR & RCC_CR_HSION) == 0){}
// Set ADC clock to HSI divided by 2
RCC->CFGR &= ~RCC_CFGR_ADCPRE; // Clear ADC prescaler bits
RCC->CFGR |= RCC_CFGR_ADCPRE_DIV2; // HSI divided by 2, now clock is 4Mhz
// Set ADC sampling time for channel 16 (Temperature sensor) in SMPR1 register
// While in SMPR register SMPx must be chosen for appropriate channel
// e.g. SMPR1_SMP10 for Channel 10 SMPR2_SMP0 for Channel 0
/*// Clear previous bits for channel sampling rate
ADC1->SMPR1 &= ~ADC_SMPR1_SMP16;
// Longest sampling time for channel 16 (Temperature sensor)
ADC1->SMPR1 |= (ADC_SMPR1_SMP16_2 | ADC_SMPR1_SMP16_1 | ADC_SMPR1_SMP16_0);*/
ADC1->SMPR2 &= ~ADC_SMPR2_SMP7;
// Longest sampling time for channel 7 (Voltage Divider)
ADC1->SMPR2 |= (ADC_SMPR2_SMP7_2 | ADC_SMPR2_SMP7_1 | ADC_SMPR2_SMP7_0);
/*//Turn on channel 16
//10000 is binary for decimal 16 so for channel 16 set the 5th bit of 4:0
ADC1->SQR3 |= ADC_SQR3_SQ1_4;
//Turn on Temperature Sensor and Voltage Reference this could be set at the same
//time as ADON to minimize delay
ADC1->CR2 |= ADC_CR2_TSVREFE;*/
//Align the data before beginning the conversion (reSETTING THE BIT IS right ALIGN)
ADC1->CR2 &= ~(ADC_CR2_ALIGN);
//Clear previous bits
ADC1->SQR3 &= ~(ADC_SQR3_SQ1);
//Turn on Channel 7 in binary 00111
ADC1->SQR3 |= (ADC_SQR3_SQ1_2 | ADC_SQR3_SQ1_1 | ADC_SQR3_SQ1_0);
// ENSURE ADC IS ON for CAL for 2cycles!
ADC1 -> CR2 |= (ADC_CR2_ADON | ADC_CR2_CONT); //this is = 1 cycle
//wait for ADC to turn on!
while((ADC1-> CR2 & ADC_CR2_ADON) == 0){} //this is = 2 cycles!
//It should be on by now
//TRYING CAL AGAIN...HMMM THIS SEEMS TO WORK
ADC1-> CR2 |= ADC_CR2_CAL;
ADC1-> CR2 |= ADC_CR2_CAL;
LCDSendAString("ADC CALing", 1, 1);
while((ADC1 -> CR2 & ADC_CR2_CAL) != 0){}
//Wait to finish CAL
LCDSendAString("ADC CALd", 1, 1);
/*//Write a message saying everything is ready
LCDSendAString(" Cel", 1, 1);
LCDSendAString("ADC", 6, 2);
// Cal'd 25C V=1.42 so 1.42/3.3V = 1762/4095 ADC values
float V25 = 1762.0000;
// in mV/degreeC per reference manual
float AVG_SLOPE = 0.0043; // 43mV/dC
// .0043/3.3 = 5.3359/4095
float AVGSlopeConvertedToADC = (AVG_SLOPE/3.3)*4095;*/
LCDSendAString("Trim Val", 1, 1);
while (1)
{
//Start the ADC conversion continiuously
ADC1->CR2 |= ADC_CR2_SWSTART;
//Wait for end of conversion flag
while((ADC1->SR & ADC_SR_EOC) == 0){}
//Display the ADC Data Register on the LCD
float ADCData = ADC1->DR;
/*
//Renamed to inputVoltage to match stm32 reference manual
float inputVoltage = ADCData;
float temperature = (((V25 - inputVoltage)/AVGSlopeConvertedToADC)+25);
LCDSendAFloat(temperature, 4, 1, 1);*/
//Remove artifacts
LCDSendAString(" ", 1, 2);
LCDSendAnInteger(ADCData, 4, 1, 2);
//set a delay so there the LCD isn't a blur
nonExactTimeDelay(1000000);
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
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_HSI;
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();
}
}
/* 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 */
Solved! Go to Solution.
2023-12-12 09:11 AM
Well, I'll be damned - right after I post the question, I figure it out... it works fine if you set up the sampling rate and all that jazz after the CAL portion... didn't think that would matter much. Here is the full code for anyone else experiencing similar issues:
#include "main.h"
#include "LCDFunctions.h"
void SystemClock_Config(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
InitializePortsForLCD();
InitializeTheLCDDisplayAndModes();
// Enable the ADC Clock Interface
RCC-> APB2ENR |= RCC_APB2ENR_ADC1EN;
//Turn on the HighSpeedInternal 8Mhz clock
RCC-> CR |= RCC_CR_HSION;
//wait for the clock to turn on
while((RCC->CR & RCC_CR_HSION) == 0){}
// Set ADC clock to HSI divided by 2
RCC->CFGR &= ~RCC_CFGR_ADCPRE; // Clear ADC prescaler bits
RCC->CFGR |= RCC_CFGR_ADCPRE_DIV2; // HSI divided by 2, now clock is 4Mhz
// Set ADC sampling time for channel 16 (Temperature sensor) in SMPR1 register
// While in SMPR register SMPx must be chosen for appropriate channel
// e.g. SMPR1_SMP10 for Channel 10 SMPR2_SMP0 for Channel 0
/*// Clear previous bits for channel sampling rate
ADC1->SMPR1 &= ~ADC_SMPR1_SMP16;
// Longest sampling time for channel 16 (Temperature sensor)
ADC1->SMPR1 |= (ADC_SMPR1_SMP16_2 | ADC_SMPR1_SMP16_1 | ADC_SMPR1_SMP16_0);*/
// ENSURE ADC IS ON for CAL for 2cycles!
ADC1 -> CR2 |= (ADC_CR2_ADON | ADC_CR2_CONT); //this is = 1 cycle
//wait for ADC to turn on!
while((ADC1-> CR2 & ADC_CR2_ADON) == 0){} //this is = 2 cycles!
//It should be on by now
//TRYING CAL AGAIN...HMMM THIS SEEMS TO WORK
ADC1-> CR2 |= ADC_CR2_CAL;
//ADC1-> CR2 |= ADC_CR2_CAL;
LCDSendAString("ADC CALing", 1, 1);
while((ADC1 -> CR2 & ADC_CR2_CAL) != 0){}
//Wait to finish CAL
LCDSendAString("ADC CALd", 1, 1);
ADC1->SMPR2 &= ~ADC_SMPR2_SMP7;
// Longest sampling time for channel 7 (Voltage Divider)
ADC1->SMPR2 |= (ADC_SMPR2_SMP7_2 | ADC_SMPR2_SMP7_1 | ADC_SMPR2_SMP7_0);
/*//Turn on channel 16
//10000 is binary for decimal 16 so for channel 16 set the 5th bit of 4:0
ADC1->SQR3 |= ADC_SQR3_SQ1_4;
//Turn on Temperature Sensor and Voltage Reference this could be set at the same
//time as ADON to minimize delay
ADC1->CR2 |= ADC_CR2_TSVREFE;*/
//Align the data before beginning the conversion (reSETTING THE BIT IS right ALIGN)
ADC1->CR2 &= ~(ADC_CR2_ALIGN);
//Clear previous bits
ADC1->SQR3 &= ~(ADC_SQR3_SQ1);
//Turn on Channel 7 in binary 00111
ADC1->SQR3 |= (ADC_SQR3_SQ1_2 | ADC_SQR3_SQ1_1 | ADC_SQR3_SQ1_0);
/*//Write a message saying everything is ready
LCDSendAString(" Cel", 1, 1);
LCDSendAString("ADC", 6, 2);
// Cal'd 25C V=1.42 so 1.42/3.3V = 1762/4095 ADC values
float V25 = 1762.0000;
// in mV/degreeC per reference manual
float AVG_SLOPE = 0.0043; // 43mV/dC
// .0043/3.3 = 5.3359/4095
float AVGSlopeConvertedToADC = (AVG_SLOPE/3.3)*4095;*/
LCDSendAString("Trim Val", 1, 1);
while (1)
{
//Start the ADC conversion continiuously
ADC1->CR2 |= ADC_CR2_SWSTART;
//Wait for end of conversion flag
while((ADC1->SR & ADC_SR_EOC) == 0){}
//Display the ADC Data Register on the LCD
float ADCData = ADC1->DR;
/*
//Renamed to inputVoltage to match stm32 reference manual
float inputVoltage = ADCData;
float temperature = (((V25 - inputVoltage)/AVGSlopeConvertedToADC)+25);
LCDSendAFloat(temperature, 4, 1, 1);*/
//Remove artifacts
LCDSendAString(" ", 1, 2);
LCDSendAnInteger(ADCData, 4, 1, 2);
//set a delay so there the LCD isn't a blur
nonExactTimeDelay(1000000);
}
}
2023-12-12 09:11 AM
Well, I'll be damned - right after I post the question, I figure it out... it works fine if you set up the sampling rate and all that jazz after the CAL portion... didn't think that would matter much. Here is the full code for anyone else experiencing similar issues:
#include "main.h"
#include "LCDFunctions.h"
void SystemClock_Config(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
InitializePortsForLCD();
InitializeTheLCDDisplayAndModes();
// Enable the ADC Clock Interface
RCC-> APB2ENR |= RCC_APB2ENR_ADC1EN;
//Turn on the HighSpeedInternal 8Mhz clock
RCC-> CR |= RCC_CR_HSION;
//wait for the clock to turn on
while((RCC->CR & RCC_CR_HSION) == 0){}
// Set ADC clock to HSI divided by 2
RCC->CFGR &= ~RCC_CFGR_ADCPRE; // Clear ADC prescaler bits
RCC->CFGR |= RCC_CFGR_ADCPRE_DIV2; // HSI divided by 2, now clock is 4Mhz
// Set ADC sampling time for channel 16 (Temperature sensor) in SMPR1 register
// While in SMPR register SMPx must be chosen for appropriate channel
// e.g. SMPR1_SMP10 for Channel 10 SMPR2_SMP0 for Channel 0
/*// Clear previous bits for channel sampling rate
ADC1->SMPR1 &= ~ADC_SMPR1_SMP16;
// Longest sampling time for channel 16 (Temperature sensor)
ADC1->SMPR1 |= (ADC_SMPR1_SMP16_2 | ADC_SMPR1_SMP16_1 | ADC_SMPR1_SMP16_0);*/
// ENSURE ADC IS ON for CAL for 2cycles!
ADC1 -> CR2 |= (ADC_CR2_ADON | ADC_CR2_CONT); //this is = 1 cycle
//wait for ADC to turn on!
while((ADC1-> CR2 & ADC_CR2_ADON) == 0){} //this is = 2 cycles!
//It should be on by now
//TRYING CAL AGAIN...HMMM THIS SEEMS TO WORK
ADC1-> CR2 |= ADC_CR2_CAL;
//ADC1-> CR2 |= ADC_CR2_CAL;
LCDSendAString("ADC CALing", 1, 1);
while((ADC1 -> CR2 & ADC_CR2_CAL) != 0){}
//Wait to finish CAL
LCDSendAString("ADC CALd", 1, 1);
ADC1->SMPR2 &= ~ADC_SMPR2_SMP7;
// Longest sampling time for channel 7 (Voltage Divider)
ADC1->SMPR2 |= (ADC_SMPR2_SMP7_2 | ADC_SMPR2_SMP7_1 | ADC_SMPR2_SMP7_0);
/*//Turn on channel 16
//10000 is binary for decimal 16 so for channel 16 set the 5th bit of 4:0
ADC1->SQR3 |= ADC_SQR3_SQ1_4;
//Turn on Temperature Sensor and Voltage Reference this could be set at the same
//time as ADON to minimize delay
ADC1->CR2 |= ADC_CR2_TSVREFE;*/
//Align the data before beginning the conversion (reSETTING THE BIT IS right ALIGN)
ADC1->CR2 &= ~(ADC_CR2_ALIGN);
//Clear previous bits
ADC1->SQR3 &= ~(ADC_SQR3_SQ1);
//Turn on Channel 7 in binary 00111
ADC1->SQR3 |= (ADC_SQR3_SQ1_2 | ADC_SQR3_SQ1_1 | ADC_SQR3_SQ1_0);
/*//Write a message saying everything is ready
LCDSendAString(" Cel", 1, 1);
LCDSendAString("ADC", 6, 2);
// Cal'd 25C V=1.42 so 1.42/3.3V = 1762/4095 ADC values
float V25 = 1762.0000;
// in mV/degreeC per reference manual
float AVG_SLOPE = 0.0043; // 43mV/dC
// .0043/3.3 = 5.3359/4095
float AVGSlopeConvertedToADC = (AVG_SLOPE/3.3)*4095;*/
LCDSendAString("Trim Val", 1, 1);
while (1)
{
//Start the ADC conversion continiuously
ADC1->CR2 |= ADC_CR2_SWSTART;
//Wait for end of conversion flag
while((ADC1->SR & ADC_SR_EOC) == 0){}
//Display the ADC Data Register on the LCD
float ADCData = ADC1->DR;
/*
//Renamed to inputVoltage to match stm32 reference manual
float inputVoltage = ADCData;
float temperature = (((V25 - inputVoltage)/AVGSlopeConvertedToADC)+25);
LCDSendAFloat(temperature, 4, 1, 1);*/
//Remove artifacts
LCDSendAString(" ", 1, 2);
LCDSendAnInteger(ADCData, 4, 1, 2);
//set a delay so there the LCD isn't a blur
nonExactTimeDelay(1000000);
}
}