Make Safety ADC use sequnece feature of ADC and use DMA to write data

This commit is contained in:
Mario Hüttel 2020-11-30 00:01:26 +01:00
parent 898feac168
commit 91d9db6a4e
7 changed files with 101 additions and 74 deletions

View File

@ -382,7 +382,7 @@ void DMA2_Stream0_IRQHandler(void)
uint32_t lisr;
float adc_val;
lisr = DMA2->LISR;
lisr = DMA2->LISR & (0x3F);
DMA2->LIFCR = lisr;
if (lisr & DMA_LISR_TCIF0) {

View File

@ -34,5 +34,8 @@
#define SAFETY_ADC_TEMP_NOM_MV 760.0f
#define SAFETY_ADC_TEMP_MV_SLOPE 2.5f
#define SAFETY_ADC_NUM_OF_CHANNELS 2
#define SAFETY_ADC_CHANNELS TEMP_CHANNEL_NUM, INT_REF_CHANNEL_NUM
#endif /* __SAFETY_ADC_HWCFG_H__ */

View File

@ -31,20 +31,20 @@
enum safety_adc_meas_channel {SAFETY_ADC_MEAS_VREF, SAFETY_ADC_MEAS_TEMP};
void safety_adc_init();
void safety_adc_init(void);
void safety_adc_deinit();
void safety_adc_deinit(void);
void safety_adc_trigger_meas(enum safety_adc_meas_channel measurement);
void safety_adc_trigger_meas(void);
/**
* @brief Poll ADC result.
* @param results adc results
* @return 1 if measurement successful, 0 if not ready, -1 if ADC aborted or not started
*/
int safety_adc_poll_result(uint16_t *adc_result);
int safety_adc_poll_result(void);
enum safety_adc_check_result handle_safety_adc();
const uint16_t *safety_adc_get_values(void);
float safety_adc_convert_channel(enum safety_adc_meas_channel channel, uint16_t analog_value);

View File

@ -101,7 +101,7 @@ enum analog_value_monitor {
*/
#define MEAS_ADC_SAFETY_FLAG_KEY 0xe554dac3UL
#define SAFETY_CONTROLLER_ADC_DELAY_MS 120
#define SAFETY_CONTROLLER_ADC_DELAY_MS 250
#define SAFETY_CONFIG_DEFAULT_PERSIST ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_MEAS_ADC_OFF, false), \
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_MEAS_ADC_WATCHDOG, false), \
@ -132,7 +132,7 @@ enum analog_value_monitor {
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_STACK, SAFETY_FLAG_CONFIG_WEIGHT_PANIC), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_SAFETY_ADC, SAFETY_FLAG_CONFIG_WEIGHT_PANIC), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_SYSTICK, SAFETY_FLAG_CONFIG_WEIGHT_PANIC), \
/* Watchdog timeout is not handled perioodically, but only on startup.
/* Watchdog timeout is not handled periodically, but only on startup.
* Therefore, it is not listed here */\
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_WTCHDG_FIRED, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_UNCAL, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \

View File

@ -233,7 +233,7 @@ void sdio_wait_ms(uint32_t ms)
*/
void DMA2_Stream7_IRQHandler(void)
{
uint32_t hisr = DMA2->HISR;
uint32_t hisr = DMA2->HISR & (0x3F << 22);
DMA2->HIFCR = hisr;

View File

@ -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;
}
}
/** @} */

View File

@ -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();
}
}
/**