Add DMA ring buffer file for UART, Improve calculation of PT1000 resistance
This commit is contained in:
		@@ -12,8 +12,11 @@ static float filter_alpha;
 | 
				
			|||||||
static volatile float pt1000_res_raw_lf;
 | 
					static volatile float pt1000_res_raw_lf;
 | 
				
			||||||
static volatile bool filter_ready;
 | 
					static volatile bool filter_ready;
 | 
				
			||||||
static volatile enum adc_pt1000_error pt1000_error;
 | 
					static volatile enum adc_pt1000_error pt1000_error;
 | 
				
			||||||
static volatile uint8_t * volatile dma_flag_ptr = NULL;
 | 
					static volatile uint8_t * volatile streaming_flag_ptr = NULL;
 | 
				
			||||||
static uint32_t filter_startup_cnt;
 | 
					static uint32_t filter_startup_cnt;
 | 
				
			||||||
 | 
					static volatile float adc_pt1000_raw_reading_hf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static volatile uint16_t dma_sample_buffer[ADC_PT1000_DMA_AVG_SAMPLES];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ADC_TO_RES(adc) ((float)(adc) / 4096.0f * 2500.0f)
 | 
					#define ADC_TO_RES(adc) ((float)(adc) / 4096.0f * 2500.0f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -50,6 +53,54 @@ static inline void adc_pt1000_disable_adc()
 | 
				
			|||||||
	rcc_manager_disable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(ADC_PT1000_PORT_RCC_MASK));
 | 
						rcc_manager_disable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(ADC_PT1000_PORT_RCC_MASK));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Enable DMA Stream for ADC
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * DMA2 Stream 0 is used. It will capture @ref ADC_PT1000_DMA_AVG_SAMPLES measurement values,
 | 
				
			||||||
 | 
					 * delete the two most extreme values
 | 
				
			||||||
 | 
					 * and calculate the avereage over the remaining values. This ensures, that one time errors are
 | 
				
			||||||
 | 
					 * not included in the measurement.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * After that, the moving average filter is fed with the values.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void adc_pt1000_enable_dma_stream()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* Enable peripheral clock for DMA2 */
 | 
				
			||||||
 | 
						rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(RCC_AHB1ENR_DMA2EN));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Destination is the DMA sample buffer */
 | 
				
			||||||
 | 
						DMA2_Stream0->M0AR = (uint32_t)dma_sample_buffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Source is the ADC data register */
 | 
				
			||||||
 | 
						DMA2_Stream0->PAR = (uint32_t)&ADC1->DR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Transfer size is ADC_PT1000_DMA_AVG_SAMPLES */
 | 
				
			||||||
 | 
						DMA2_Stream0->NDTR = ADC_PT1000_DMA_AVG_SAMPLES;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						NVIC_EnableIRQ(DMA2_Stream0_IRQn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Enable the stream in Peripheral-to-Memory mode with 16 bit data and a circular destination buffer
 | 
				
			||||||
 | 
						 * Enable interrupt generation on transfer complete
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * Todo: Maybe use twice as big of a buffer and also use half-fill interrupt in order to prevent overruns
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						DMA2_Stream0->CR = DMA_SxCR_PL_1 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PSIZE_0 | DMA_SxCR_MINC |
 | 
				
			||||||
 | 
								DMA_SxCR_CIRC | DMA_SxCR_TCIE | DMA_SxCR_EN;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void adc_pt1000_disable_dma_stream()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* Disable the stream */
 | 
				
			||||||
 | 
						DMA2_Stream0->CR = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Disable clock if necessary */
 | 
				
			||||||
 | 
						rcc_manager_disable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(RCC_AHB1ENR_DMA2EN));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Disable interrupt */
 | 
				
			||||||
 | 
						NVIC_DisableIRQ(DMA2_Stream0_IRQn);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void adc_pt1000_setup_meas()
 | 
					void adc_pt1000_setup_meas()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	rcc_manager_enable_clock(&RCC->APB2ENR, BITMASK_TO_BITNO(RCC_APB2ENR_ADC1EN));
 | 
						rcc_manager_enable_clock(&RCC->APB2ENR, BITMASK_TO_BITNO(RCC_APB2ENR_ADC1EN));
 | 
				
			||||||
@@ -76,8 +127,8 @@ void adc_pt1000_setup_meas()
 | 
				
			|||||||
	/* Set channel as 1st element in sequence */
 | 
						/* Set channel as 1st element in sequence */
 | 
				
			||||||
	ADC1->SQR3 = (ADC_PT1000_CHANNEL<<0);
 | 
						ADC1->SQR3 = (ADC_PT1000_CHANNEL<<0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ADC1->CR1 = ADC_CR1_OVRIE | ADC_CR1_AWDEN | ADC_CR1_EOCIE;
 | 
						ADC1->CR1 = ADC_CR1_OVRIE | ADC_CR1_AWDEN | ADC_CR1_AWDIE;
 | 
				
			||||||
	ADC1->CR2 = ADC_CR2_EXTEN_0 | ADC_CR2_EXTSEL_2 | ADC_CR2_EXTSEL_1 | ADC_CR2_ADON;
 | 
						ADC1->CR2 = ADC_CR2_EXTEN_0 | ADC_CR2_EXTSEL_2 | ADC_CR2_EXTSEL_1 | ADC_CR2_ADON | ADC_CR2_DMA | ADC_CR2_DDS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	adc_pt1000_set_moving_average_filter_param(ADC_PT1000_FILTER_WEIGHT);
 | 
						adc_pt1000_set_moving_average_filter_param(ADC_PT1000_FILTER_WEIGHT);
 | 
				
			||||||
	adc_pt1000_set_resistance_calibration(0, 0, false);
 | 
						adc_pt1000_set_resistance_calibration(0, 0, false);
 | 
				
			||||||
@@ -85,7 +136,7 @@ void adc_pt1000_setup_meas()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	NVIC_EnableIRQ(ADC_IRQn);
 | 
						NVIC_EnableIRQ(ADC_IRQn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN;
 | 
						adc_pt1000_enable_dma_stream();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	adc_pt1000_setup_sample_frequency_timer();
 | 
						adc_pt1000_setup_sample_frequency_timer();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -170,21 +221,49 @@ void adc_pt1000_disable()
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	adc_pt1000_disable_adc();
 | 
						adc_pt1000_disable_adc();
 | 
				
			||||||
	adc_pt1000_stop_sample_frequency_timer();
 | 
						adc_pt1000_stop_sample_frequency_timer();
 | 
				
			||||||
 | 
						adc_pt1000_disable_dma_stream();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	filter_ready = false;
 | 
						filter_ready = false;
 | 
				
			||||||
	pt1000_res_raw_lf = 0.0f;
 | 
						pt1000_res_raw_lf = 0.0f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (dma_flag_ptr) {
 | 
						if (streaming_flag_ptr) {
 | 
				
			||||||
		*dma_flag_ptr = -3;
 | 
							*streaming_flag_ptr = -3;
 | 
				
			||||||
		dma_flag_ptr = NULL;
 | 
							streaming_flag_ptr = NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline __attribute__((optimize("O3"))) void adc_pt1000_filter(uint16_t adc_value)
 | 
					static inline __attribute__((optimize("O3"))) void adc_pt1000_filter(float adc_prefiltered_value)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!filter_ready && --filter_startup_cnt <= 0)
 | 
						if (!filter_ready && --filter_startup_cnt <= 0)
 | 
				
			||||||
		filter_ready = true;
 | 
							filter_ready = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pt1000_res_raw_lf = (1-filter_alpha) * pt1000_res_raw_lf + filter_alpha * ADC_TO_RES((float)adc_value);
 | 
						pt1000_res_raw_lf = (1.0f-filter_alpha) * pt1000_res_raw_lf + filter_alpha * ADC_TO_RES(adc_prefiltered_value);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline __attribute__((optimize("O3"))) float adc_pt1000_dma_avg_pre_filter()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						uint32_t sum = 0;
 | 
				
			||||||
 | 
						uint16_t max_val = 0U;
 | 
				
			||||||
 | 
						uint16_t min_val = 65535U;
 | 
				
			||||||
 | 
						uint16_t sample;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < ADC_PT1000_DMA_AVG_SAMPLES; i++) {
 | 
				
			||||||
 | 
							sample = dma_sample_buffer[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Update min and max trackers */
 | 
				
			||||||
 | 
							max_val = (sample > max_val ? sample : max_val);
 | 
				
			||||||
 | 
							min_val = (sample < min_val ? sample : min_val);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Sum up all values (for average) */
 | 
				
			||||||
 | 
							sum += sample;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Delete max and min vals from sum */
 | 
				
			||||||
 | 
						sum = sum - (uint32_t)max_val - (uint32_t)min_val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Divide to get average and return */
 | 
				
			||||||
 | 
						return (float)sum / (ADC_PT1000_DMA_AVG_SAMPLES-2);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ADC_IRQHandler(void)
 | 
					void ADC_IRQHandler(void)
 | 
				
			||||||
@@ -192,19 +271,15 @@ void ADC_IRQHandler(void)
 | 
				
			|||||||
	uint32_t adc1_sr;
 | 
						uint32_t adc1_sr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	adc1_sr = ADC1->SR;
 | 
						adc1_sr = ADC1->SR;
 | 
				
			||||||
	if (ADC1->SR & ADC_SR_EOC) {
 | 
					 | 
				
			||||||
		ADC1->SR &= ~ADC_SR_EOC;
 | 
					 | 
				
			||||||
		adc_pt1000_filter(ADC1->DR);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (adc1_sr & ADC_SR_OVR) {
 | 
						if (adc1_sr & ADC_SR_OVR) {
 | 
				
			||||||
		ADC1->SR &= ~ADC_SR_OVR;
 | 
							ADC1->SR &= ~ADC_SR_OVR;
 | 
				
			||||||
		pt1000_error |= ADC_PT1000_OVERFLOW;
 | 
							pt1000_error |= ADC_PT1000_OVERFLOW;
 | 
				
			||||||
		/* Disable ADC  in case of overrrun*/
 | 
							/* Disable ADC  in case of overrrun*/
 | 
				
			||||||
		adc_pt1000_disable();
 | 
							adc_pt1000_disable();
 | 
				
			||||||
		if (dma_flag_ptr) {
 | 
							if (streaming_flag_ptr) {
 | 
				
			||||||
			*dma_flag_ptr = -1;
 | 
								*streaming_flag_ptr = -1;
 | 
				
			||||||
			dma_flag_ptr = NULL;
 | 
								streaming_flag_ptr = NULL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -217,18 +292,23 @@ void ADC_IRQHandler(void)
 | 
				
			|||||||
void DMA2_Stream0_IRQHandler()
 | 
					void DMA2_Stream0_IRQHandler()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	uint32_t lisr;
 | 
						uint32_t lisr;
 | 
				
			||||||
 | 
						float adc_val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	lisr = DMA2->LISR;
 | 
						lisr = DMA2->LISR;
 | 
				
			||||||
	DMA2->LIFCR = lisr;
 | 
						DMA2->LIFCR = lisr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (lisr & DMA_LISR_TCIF0 && dma_flag_ptr) {
 | 
						if (lisr & DMA_LISR_TCIF0) {
 | 
				
			||||||
		*dma_flag_ptr = 1;
 | 
							/* Samples Transfered */
 | 
				
			||||||
		dma_flag_ptr = NULL;
 | 
							adc_val = adc_pt1000_dma_avg_pre_filter();
 | 
				
			||||||
 | 
							adc_pt1000_raw_reading_hf = adc_val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Call moving average filter */
 | 
				
			||||||
 | 
							adc_pt1000_filter(adc_val);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (lisr & DMA_LISR_TEIF0 && dma_flag_ptr) {
 | 
						if (lisr & DMA_LISR_TEIF0) {
 | 
				
			||||||
		*dma_flag_ptr = -2;
 | 
							/* Wait for watchdog to kick in */
 | 
				
			||||||
		dma_flag_ptr = NULL;
 | 
							while(1);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,30 +12,32 @@
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * @brief ADC channel number of PT1000 sensor input
 | 
					 * @brief ADC channel number of PT1000 sensor input
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#define ADC_PT1000_CHANNEL 2
 | 
					#define ADC_PT1000_CHANNEL 2U
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ADC_PT1000_PORT GPIOA
 | 
					#define ADC_PT1000_PORT GPIOA
 | 
				
			||||||
#define ADC_PT1000_PORT_RCC_MASK RCC_AHB1ENR_GPIOAEN
 | 
					#define ADC_PT1000_PORT_RCC_MASK RCC_AHB1ENR_GPIOAEN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ADC_PT1000_PIN 2
 | 
					#define ADC_PT1000_PIN 2U
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ADC_FILTER_STARTUP_CYCLES 800
 | 
					#define ADC_FILTER_STARTUP_CYCLES 800U
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ADC_PT1000_SAMPLE_CNT_DELAY 2000
 | 
					#define ADC_PT1000_SAMPLE_CNT_DELAY 1000U
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ADC_PT1000_DMA_AVG_SAMPLES 6U
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @brief Lower value for valid input range for PT1000 measurement
 | 
					 * @brief Lower value for valid input range for PT1000 measurement
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * If the input of the PT1000 sensor is below this value, an error is thrown. This is used to disable the temperature control loop
 | 
					 * If the input of the PT1000 sensor is below this value, an error is thrown. This is used to disable the temperature control loop
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#define ADC_PT1000_LOWER_WATCHDOG 100
 | 
					#define ADC_PT1000_LOWER_WATCHDOG 200U
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @brief Upper value for valid input range for PT1000 measurement
 | 
					 * @brief Upper value for valid input range for PT1000 measurement
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * If the input of the PT1000 sensor is above this value, an error is thrown. This is used to disable the temperature control loop
 | 
					 * If the input of the PT1000 sensor is above this value, an error is thrown. This is used to disable the temperature control loop
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#define ADC_PT1000_UPPER_WATCHDOG 4000
 | 
					#define ADC_PT1000_UPPER_WATCHDOG 4000U
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum adc_pt1000_error {ADC_PT1000_NO_ERR= 0, ADC_PT1000_WATCHDOG_ERROR=(1UL<<0), ADC_PT1000_OVERFLOW=(1UL<<1)};
 | 
					enum adc_pt1000_error {ADC_PT1000_NO_ERR= 0, ADC_PT1000_WATCHDOG_ERROR=(1UL<<0), ADC_PT1000_OVERFLOW=(1UL<<1)};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								stm-firmware/include/uart/dma-ring-buffer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								stm-firmware/include/uart/dma-ring-buffer.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					#ifndef __DMA_RING_BUFFER_H__
 | 
				
			||||||
 | 
					#define __DMA_RING_BUFFER_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* __DMA_RING_BUFFER_H__ */
 | 
				
			||||||
@@ -20,8 +20,8 @@ static void setup_nvic_priorities()
 | 
				
			|||||||
	NVIC_SetPriorityGrouping(2);
 | 
						NVIC_SetPriorityGrouping(2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Setup Priorities */
 | 
						/* Setup Priorities */
 | 
				
			||||||
	NVIC_SetPriority(ADC_IRQn, 1);
 | 
						NVIC_SetPriority(ADC_IRQn, 2);
 | 
				
			||||||
	NVIC_SetPriority(DMA2_Stream0_IRQn, 2);
 | 
						NVIC_SetPriority(DMA2_Stream0_IRQn, 1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static float pt1000_value;
 | 
					static float pt1000_value;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								stm-firmware/uart/dma-ring-buffer.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								stm-firmware/uart/dma-ring-buffer.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					#include <uart/dma-ring-buffer.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Reference in New Issue
	
	Block a user