Make Safety ADC use sequnece feature of ADC and use DMA to write data
This commit is contained in:
		@@ -28,9 +28,17 @@
 | 
			
		||||
#include <helper-macros/helper-macros.h>
 | 
			
		||||
#include <stm-periph/clock-enable-manager.h>
 | 
			
		||||
 | 
			
		||||
void safety_adc_init()
 | 
			
		||||
static const uint8_t safety_adc_channels[SAFETY_ADC_NUM_OF_CHANNELS] = {SAFETY_ADC_CHANNELS};
 | 
			
		||||
static volatile uint8_t safety_adc_conversion_complete;
 | 
			
		||||
static volatile uint8_t safety_adc_triggered;
 | 
			
		||||
static volatile uint16_t safety_adc_conversions[SAFETY_ADC_NUM_OF_CHANNELS];
 | 
			
		||||
 | 
			
		||||
void safety_adc_init(void)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	rcc_manager_enable_clock(&RCC->APB2ENR, BITMASK_TO_BITNO(SAFETY_ADC_ADC_RCC_MASK));
 | 
			
		||||
	rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(RCC_AHB1ENR_DMA2EN));
 | 
			
		||||
 | 
			
		||||
	/* Enable temperature and VREFINT measurement */
 | 
			
		||||
	ADC->CCR |= ADC_CCR_TSVREFE;
 | 
			
		||||
@@ -38,17 +46,48 @@ void safety_adc_init()
 | 
			
		||||
	/* Set sample time for channels 16 and 17 */
 | 
			
		||||
	SAFETY_ADC_ADC_PERIPHERAL->SMPR1 |= ADC_SMPR1_SMP17 | ADC_SMPR1_SMP16;
 | 
			
		||||
 | 
			
		||||
	/* Standard sequence. One measurement */
 | 
			
		||||
	SAFETY_ADC_ADC_PERIPHERAL->SQR1 = 0UL;
 | 
			
		||||
	/* Standard sequence. Measure all channels in one sequence */
 | 
			
		||||
	SAFETY_ADC_ADC_PERIPHERAL->SQR1 = (SAFETY_ADC_NUM_OF_CHANNELS - 1) << 20 ;
 | 
			
		||||
	SAFETY_ADC_ADC_PERIPHERAL->SQR2 = 0UL;
 | 
			
		||||
	SAFETY_ADC_ADC_PERIPHERAL->SQR3 = 0UL;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < SAFETY_ADC_NUM_OF_CHANNELS; i++) {
 | 
			
		||||
		switch (i) {
 | 
			
		||||
		case 0 ... 5:
 | 
			
		||||
			SAFETY_ADC_ADC_PERIPHERAL->SQR3 |= safety_adc_channels[i] << (i * 5);
 | 
			
		||||
			break;
 | 
			
		||||
		case 6 ... 11:
 | 
			
		||||
			SAFETY_ADC_ADC_PERIPHERAL->SQR2 |= safety_adc_channels[i] << ((i-6) * 5);
 | 
			
		||||
			break;
 | 
			
		||||
		case 12 ... 15:
 | 
			
		||||
			SAFETY_ADC_ADC_PERIPHERAL->SQR1 |= safety_adc_channels[i] << ((i-12) * 5);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	safety_adc_conversion_complete = 0;
 | 
			
		||||
	safety_adc_triggered = 0;
 | 
			
		||||
 | 
			
		||||
	/* Setup the DMA to move the data */
 | 
			
		||||
	DMA2_Stream4->PAR = (uint32_t)&SAFETY_ADC_ADC_PERIPHERAL->DR;
 | 
			
		||||
	DMA2_Stream4->M0AR = (uint32_t)safety_adc_conversions;
 | 
			
		||||
	DMA2_Stream4->NDTR = SAFETY_ADC_NUM_OF_CHANNELS;
 | 
			
		||||
	DMA2_Stream4->CR = DMA_SxCR_PL_0 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PSIZE_0 | DMA_SxCR_MINC | DMA_SxCR_CIRC | DMA_SxCR_TCIE | DMA_SxCR_EN;
 | 
			
		||||
	NVIC_EnableIRQ(DMA2_Stream4_IRQn);
 | 
			
		||||
 | 
			
		||||
	/* Enable ADC */
 | 
			
		||||
	SAFETY_ADC_ADC_PERIPHERAL->CR2 = ADC_CR2_ADON | ADC_CR2_DMA | ADC_CR2_DDS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void safety_adc_deinit()
 | 
			
		||||
void safety_adc_deinit(void)
 | 
			
		||||
{
 | 
			
		||||
	SAFETY_ADC_ADC_PERIPHERAL->CR1 = 0UL;
 | 
			
		||||
	SAFETY_ADC_ADC_PERIPHERAL->CR2 = 0UL;
 | 
			
		||||
	SAFETY_ADC_ADC_PERIPHERAL->SMPR1  = 0UL;
 | 
			
		||||
	rcc_manager_enable_clock(&RCC->APB1ENR, BITMASK_TO_BITNO(RCC_APB2ENR_ADC2EN));
 | 
			
		||||
	rcc_manager_disable_clock(&RCC->APB1ENR, BITMASK_TO_BITNO(RCC_APB2ENR_ADC2EN));
 | 
			
		||||
	DMA2_Stream4->CR = 0;
 | 
			
		||||
	rcc_manager_disable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(RCC_AHB1ENR_DMA2EN));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float safety_adc_convert_channel(enum safety_adc_meas_channel channel, uint16_t analog_value)
 | 
			
		||||
@@ -72,42 +111,44 @@ float safety_adc_convert_channel(enum safety_adc_meas_channel channel, uint16_t
 | 
			
		||||
	return converted_val;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int safety_adc_poll_result(uint16_t *adc_result)
 | 
			
		||||
int safety_adc_poll_result(void)
 | 
			
		||||
{
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
	if (safety_adc_triggered)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (!adc_result)
 | 
			
		||||
		return -1000;
 | 
			
		||||
 | 
			
		||||
	if (!(SAFETY_ADC_ADC_PERIPHERAL->CR2 & ADC_CR2_ADON)) {
 | 
			
		||||
	if (safety_adc_conversion_complete)
 | 
			
		||||
		return 1;
 | 
			
		||||
	else
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (SAFETY_ADC_ADC_PERIPHERAL->SR & ADC_SR_EOC) {
 | 
			
		||||
		*adc_result = (uint16_t)SAFETY_ADC_ADC_PERIPHERAL->DR;
 | 
			
		||||
		SAFETY_ADC_ADC_PERIPHERAL->CR2 &= ~ADC_CR2_ADON;
 | 
			
		||||
		ret = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void safety_adc_trigger_meas(enum safety_adc_meas_channel measurement)
 | 
			
		||||
const uint16_t *safety_adc_get_values(void)
 | 
			
		||||
{
 | 
			
		||||
	switch (measurement) {
 | 
			
		||||
	case SAFETY_ADC_MEAS_TEMP:
 | 
			
		||||
		SAFETY_ADC_ADC_PERIPHERAL->SQR3 = TEMP_CHANNEL_NUM;
 | 
			
		||||
		break;
 | 
			
		||||
	case SAFETY_ADC_MEAS_VREF:
 | 
			
		||||
		SAFETY_ADC_ADC_PERIPHERAL->SQR3 = INT_REF_CHANNEL_NUM;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	safety_adc_conversion_complete = 0;
 | 
			
		||||
	return (const uint16_t *)safety_adc_conversions;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void safety_adc_trigger_meas(void)
 | 
			
		||||
{
 | 
			
		||||
	safety_adc_conversion_complete = 0;
 | 
			
		||||
 | 
			
		||||
	SAFETY_ADC_ADC_PERIPHERAL->CR1 |= ADC_CR1_SCAN;
 | 
			
		||||
	SAFETY_ADC_ADC_PERIPHERAL->CR2 |= ADC_CR2_ADON;
 | 
			
		||||
	SAFETY_ADC_ADC_PERIPHERAL->CR2 |= ADC_CR2_SWSTART;
 | 
			
		||||
	safety_adc_triggered = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DMA2_Stream4_IRQHandler()
 | 
			
		||||
{
 | 
			
		||||
	uint32_t hisr;
 | 
			
		||||
 | 
			
		||||
	hisr = DMA2->HISR & 0x3F;
 | 
			
		||||
	DMA2->HIFCR = hisr;
 | 
			
		||||
 | 
			
		||||
	if (hisr & DMA_HISR_TCIF4) {
 | 
			
		||||
		safety_adc_triggered = 0;
 | 
			
		||||
		safety_adc_conversion_complete = 1;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
 
 | 
			
		||||
@@ -536,46 +536,29 @@ static void safety_controller_check_stack()
 | 
			
		||||
 | 
			
		||||
static void safety_controller_handle_safety_adc()
 | 
			
		||||
{
 | 
			
		||||
	static enum safety_adc_meas_channel current_channel = SAFETY_ADC_MEAS_TEMP;
 | 
			
		||||
	static uint64_t last_result_timestamp = 0;
 | 
			
		||||
	const uint16_t *channels;
 | 
			
		||||
	int poll_result;
 | 
			
		||||
	uint16_t result;
 | 
			
		||||
	float analog_value;
 | 
			
		||||
 | 
			
		||||
	poll_result = safety_adc_poll_result(&result);
 | 
			
		||||
	if (!systick_ticks_have_passed(last_result_timestamp, SAFETY_CONTROLLER_ADC_DELAY_MS) && poll_result != 1)
 | 
			
		||||
		return;
 | 
			
		||||
	poll_result = safety_adc_poll_result();
 | 
			
		||||
 | 
			
		||||
	if (poll_result) {
 | 
			
		||||
		if (poll_result == -1) {
 | 
			
		||||
			switch (current_channel) {
 | 
			
		||||
			case SAFETY_ADC_MEAS_TEMP:
 | 
			
		||||
				current_channel = SAFETY_ADC_MEAS_VREF;
 | 
			
		||||
				break;
 | 
			
		||||
			case SAFETY_ADC_MEAS_VREF:
 | 
			
		||||
				/* Expected fallthru */
 | 
			
		||||
			default:
 | 
			
		||||
				current_channel = SAFETY_ADC_MEAS_TEMP;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
			safety_adc_trigger_meas(current_channel);
 | 
			
		||||
		} else if (poll_result == 1) {
 | 
			
		||||
			last_result_timestamp = systick_get_global_tick();
 | 
			
		||||
			analog_value = safety_adc_convert_channel(current_channel, result);
 | 
			
		||||
			safety_controller_report_timing(ERR_TIMING_SAFETY_ADC);
 | 
			
		||||
			switch (current_channel) {
 | 
			
		||||
			case SAFETY_ADC_MEAS_TEMP:
 | 
			
		||||
				safety_controller_report_analog_value(ERR_AMON_UC_TEMP, analog_value);
 | 
			
		||||
				break;
 | 
			
		||||
			case SAFETY_ADC_MEAS_VREF:
 | 
			
		||||
				safety_controller_report_analog_value(ERR_AMON_VREF, analog_value);
 | 
			
		||||
				break;
 | 
			
		||||
			default:
 | 
			
		||||
				safety_controller_report_error(ERR_FLAG_SAFETY_ADC);
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	if (poll_result == 1) {
 | 
			
		||||
		/* Data available */
 | 
			
		||||
		channels = safety_adc_get_values();
 | 
			
		||||
		analog_value = safety_adc_convert_channel(SAFETY_ADC_MEAS_TEMP, channels[0]);
 | 
			
		||||
		safety_controller_report_analog_value(ERR_AMON_UC_TEMP, analog_value);
 | 
			
		||||
		analog_value = safety_adc_convert_channel(SAFETY_ADC_MEAS_VREF, channels[1]);
 | 
			
		||||
		safety_controller_report_analog_value(ERR_AMON_VREF, analog_value);
 | 
			
		||||
		last_result_timestamp = systick_get_global_tick();
 | 
			
		||||
		safety_controller_report_timing(ERR_TIMING_SAFETY_ADC);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (systick_ticks_have_passed(last_result_timestamp, SAFETY_CONTROLLER_ADC_DELAY_MS)) {
 | 
			
		||||
		if (poll_result != 1 && poll_result != 0)
 | 
			
		||||
			safety_adc_trigger_meas();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user