2020-05-16 21:00:55 +02:00
|
|
|
/* Reflow Oven Controller
|
2022-07-16 13:01:38 +02:00
|
|
|
*
|
|
|
|
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
|
|
|
|
*
|
|
|
|
* This file is part of the Reflow Oven Controller Project.
|
|
|
|
*
|
|
|
|
* The reflow oven controller is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
|
|
* published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* The Reflow Oven Control Firmware is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with the reflow oven controller project.
|
|
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
2020-05-16 21:00:55 +02:00
|
|
|
|
2020-07-06 21:12:18 +02:00
|
|
|
/**
|
|
|
|
* @addtogroup safety-adc
|
|
|
|
* @{
|
|
|
|
*/
|
|
|
|
|
2020-07-06 20:13:01 +02:00
|
|
|
#include <reflow-controller/safety/safety-adc.h>
|
2020-05-16 21:00:55 +02:00
|
|
|
#include <reflow-controller/periph-config/safety-adc-hwcfg.h>
|
2020-06-14 19:09:59 +02:00
|
|
|
#include <helper-macros/helper-macros.h>
|
2020-12-01 21:00:23 +01:00
|
|
|
#include <stm-periph/rcc-manager.h>
|
2021-01-01 19:48:53 +01:00
|
|
|
#include <reflow-controller/hw-version-detect.h>
|
2021-07-23 20:06:09 +02:00
|
|
|
#include <reflow-controller/safety/safety-controller.h>
|
2020-05-16 21:00:55 +02:00
|
|
|
|
2020-11-30 00:01:26 +01:00
|
|
|
static const uint8_t safety_adc_channels[SAFETY_ADC_NUM_OF_CHANNELS] = {SAFETY_ADC_CHANNELS};
|
2021-11-28 23:40:43 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Safety ADC conversion complete. Set in interrupt.
|
|
|
|
*/
|
|
|
|
static volatile uint8_t IN_SECTION(.ccm.bss) safety_adc_conversion_complete;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Safety ADC has been started. It will perform all specified conversions and
|
|
|
|
* set @ref safety_adc_conversion_complete afterwards
|
|
|
|
*/
|
|
|
|
static volatile uint8_t IN_SECTION(.ccm.bss) safety_adc_triggered;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Safety ADC conversion storage. This is filled by DMA.
|
|
|
|
* @note Do not move this to CCM RAM as the DMA won't be able to access it.
|
|
|
|
*/
|
2020-11-30 00:01:26 +01:00
|
|
|
static volatile uint16_t safety_adc_conversions[SAFETY_ADC_NUM_OF_CHANNELS];
|
|
|
|
|
|
|
|
void safety_adc_init(void)
|
2020-05-16 21:00:55 +02:00
|
|
|
{
|
2021-01-01 19:48:53 +01:00
|
|
|
enum hw_revision hw_rev;
|
2020-11-30 00:01:26 +01:00
|
|
|
int i;
|
|
|
|
|
2021-01-01 19:48:53 +01:00
|
|
|
hw_rev = get_pcb_hardware_version();
|
|
|
|
|
2020-05-16 21:00:55 +02:00
|
|
|
rcc_manager_enable_clock(&RCC->APB2ENR, BITMASK_TO_BITNO(SAFETY_ADC_ADC_RCC_MASK));
|
2020-11-30 00:01:26 +01:00
|
|
|
rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(RCC_AHB1ENR_DMA2EN));
|
2020-05-16 21:00:55 +02:00
|
|
|
|
2021-01-01 19:48:53 +01:00
|
|
|
if (hw_rev != HW_REV_V1_2) {
|
2022-07-16 13:01:38 +02:00
|
|
|
rcc_manager_enable_clock(&RCC->AHB1ENR,
|
|
|
|
BITMASK_TO_BITNO(SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PORT_RCC_MASK));
|
2021-01-01 19:48:53 +01:00
|
|
|
SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PORT->MODER &= MODER_DELETE(SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PIN);
|
|
|
|
SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PORT->MODER |= ANALOG(SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PIN);
|
|
|
|
}
|
|
|
|
|
2020-05-16 21:00:55 +02:00
|
|
|
/* Enable temperature and VREFINT measurement */
|
|
|
|
ADC->CCR |= ADC_CCR_TSVREFE;
|
|
|
|
|
2021-01-01 19:48:53 +01:00
|
|
|
/* Set sample time for channels 16 and 17 and 15 */
|
|
|
|
SAFETY_ADC_ADC_PERIPHERAL->SMPR1 |= ADC_SMPR1_SMP17 | ADC_SMPR1_SMP16 | ADC_SMPR1_SMP15;
|
2020-05-16 21:00:55 +02:00
|
|
|
|
2020-11-30 00:01:26 +01:00
|
|
|
/* Standard sequence. Measure all channels in one sequence */
|
2022-07-16 13:01:38 +02:00
|
|
|
SAFETY_ADC_ADC_PERIPHERAL->SQR1 = (SAFETY_ADC_NUM_OF_CHANNELS - 1) << 20;
|
2020-11-30 00:01:26 +01:00
|
|
|
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;
|
2022-07-16 13:01:38 +02:00
|
|
|
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;
|
2020-11-30 00:01:26 +01:00
|
|
|
NVIC_EnableIRQ(DMA2_Stream4_IRQn);
|
|
|
|
|
|
|
|
/* Enable ADC */
|
2021-07-23 20:06:09 +02:00
|
|
|
SAFETY_ADC_ADC_PERIPHERAL->CR1 |= ADC_CR1_SCAN;
|
2020-11-30 00:01:26 +01:00
|
|
|
SAFETY_ADC_ADC_PERIPHERAL->CR2 = ADC_CR2_ADON | ADC_CR2_DMA | ADC_CR2_DDS;
|
2021-07-23 20:06:09 +02:00
|
|
|
safety_controller_set_crc_monitor(ERR_CRC_MON_SAFETY_ADC, SAFETY_CRC_MON_SAFETY_ADC_PW);
|
2020-05-16 21:00:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-11-30 00:01:26 +01:00
|
|
|
void safety_adc_deinit(void)
|
2020-05-16 21:00:55 +02:00
|
|
|
{
|
|
|
|
SAFETY_ADC_ADC_PERIPHERAL->CR1 = 0UL;
|
|
|
|
SAFETY_ADC_ADC_PERIPHERAL->CR2 = 0UL;
|
|
|
|
SAFETY_ADC_ADC_PERIPHERAL->SMPR1 = 0UL;
|
2021-07-23 20:06:09 +02:00
|
|
|
|
2020-11-30 00:01:26 +01:00
|
|
|
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));
|
2021-07-23 20:06:09 +02:00
|
|
|
safety_controller_set_crc_monitor(ERR_CRC_MON_SAFETY_ADC, SAFETY_CRC_MON_SAFETY_ADC_PW);
|
2020-05-16 21:00:55 +02:00
|
|
|
}
|
|
|
|
|
2020-07-09 22:31:42 +02:00
|
|
|
float safety_adc_convert_channel(enum safety_adc_meas_channel channel, uint16_t analog_value)
|
2020-05-16 21:00:55 +02:00
|
|
|
{
|
2020-07-09 22:31:42 +02:00
|
|
|
float converted_val;
|
2021-01-01 19:48:53 +01:00
|
|
|
enum hw_revision hw_rev;
|
2020-05-16 21:00:55 +02:00
|
|
|
|
2020-07-09 22:31:42 +02:00
|
|
|
switch (channel) {
|
|
|
|
case SAFETY_ADC_MEAS_TEMP:
|
2021-01-09 22:28:22 +01:00
|
|
|
converted_val = (((float)analog_value / 4096.0f * 2500.0f - SAFETY_ADC_TEMP_NOM_MV) /
|
2020-07-09 22:31:42 +02:00
|
|
|
SAFETY_ADC_TEMP_MV_SLOPE) + SAFETY_ADC_TEMP_NOM;
|
|
|
|
break;
|
|
|
|
case SAFETY_ADC_MEAS_VREF:
|
2021-01-09 22:28:22 +01:00
|
|
|
converted_val = (SAFETY_ADC_INT_REF_MV * 4096.0f) / (float)analog_value;
|
2020-07-09 22:31:42 +02:00
|
|
|
break;
|
2021-01-01 19:48:53 +01:00
|
|
|
case SAFETY_ADC_MEAS_SUPPLY:
|
|
|
|
hw_rev = get_pcb_hardware_version();
|
|
|
|
if (hw_rev >= HW_REV_V1_3)
|
2021-01-09 22:28:22 +01:00
|
|
|
converted_val = ((float)analog_value) / 4096.0f * 2500.0f * 2.0f;
|
2021-01-01 19:48:53 +01:00
|
|
|
else
|
|
|
|
converted_val = 3300.0f;
|
|
|
|
break;
|
2020-07-09 22:31:42 +02:00
|
|
|
default:
|
|
|
|
/* Generate NaN value as default return */
|
|
|
|
converted_val = 0.0f / 0.0f;
|
|
|
|
break;
|
2020-05-16 21:00:55 +02:00
|
|
|
}
|
|
|
|
|
2020-07-09 22:31:42 +02:00
|
|
|
return converted_val;
|
2020-05-16 21:00:55 +02:00
|
|
|
}
|
|
|
|
|
2020-11-30 00:01:26 +01:00
|
|
|
int safety_adc_poll_result(void)
|
2020-05-16 21:00:55 +02:00
|
|
|
{
|
2020-11-30 00:01:26 +01:00
|
|
|
if (safety_adc_triggered)
|
|
|
|
return 0;
|
2020-05-16 21:00:55 +02:00
|
|
|
|
2020-11-30 00:01:26 +01:00
|
|
|
if (safety_adc_conversion_complete)
|
|
|
|
return 1;
|
|
|
|
else
|
2020-05-16 21:00:55 +02:00
|
|
|
return -1;
|
2020-11-30 00:01:26 +01:00
|
|
|
}
|
2020-05-16 21:00:55 +02:00
|
|
|
|
2020-11-30 00:01:26 +01:00
|
|
|
const uint16_t *safety_adc_get_values(void)
|
|
|
|
{
|
|
|
|
safety_adc_conversion_complete = 0;
|
|
|
|
return (const uint16_t *)safety_adc_conversions;
|
2020-05-16 21:00:55 +02:00
|
|
|
}
|
|
|
|
|
2020-11-30 00:01:26 +01:00
|
|
|
void safety_adc_trigger_meas(void)
|
2020-05-16 21:00:55 +02:00
|
|
|
{
|
2020-11-30 00:01:26 +01:00
|
|
|
safety_adc_conversion_complete = 0;
|
2020-05-16 21:00:55 +02:00
|
|
|
|
2020-11-30 00:01:26 +01:00
|
|
|
SAFETY_ADC_ADC_PERIPHERAL->CR1 |= ADC_CR1_SCAN;
|
2020-05-16 21:00:55 +02:00
|
|
|
SAFETY_ADC_ADC_PERIPHERAL->CR2 |= ADC_CR2_ADON;
|
|
|
|
SAFETY_ADC_ADC_PERIPHERAL->CR2 |= ADC_CR2_SWSTART;
|
2020-11-30 00:01:26 +01:00
|
|
|
safety_adc_triggered = 1;
|
2020-05-16 21:00:55 +02:00
|
|
|
}
|
|
|
|
|
2022-07-16 13:01:38 +02:00
|
|
|
void DMA2_Stream4_IRQHandler(void)
|
2020-11-30 00:01:26 +01:00
|
|
|
{
|
|
|
|
uint32_t hisr;
|
|
|
|
|
|
|
|
hisr = DMA2->HISR & 0x3F;
|
|
|
|
DMA2->HIFCR = hisr;
|
|
|
|
|
|
|
|
if (hisr & DMA_HISR_TCIF4) {
|
|
|
|
safety_adc_triggered = 0;
|
|
|
|
safety_adc_conversion_complete = 1;
|
|
|
|
}
|
|
|
|
}
|
2020-07-06 21:12:18 +02:00
|
|
|
|
|
|
|
/** @} */
|