From a2eb84f7573871caf6405b505f09d724fd586fc9 Mon Sep 17 00:00:00 2001 From: Yilin Sun Date: Thu, 16 Mar 2023 09:42:03 +0800 Subject: [PATCH] Initial WIP ADC support. Signed-off-by: Yilin Sun --- CMakeLists.txt | 1 + lib/mruby | 2 +- src/mrb_machine_impl/mrb_machine_adc_impl.c | 127 ++++++++++++++++++++ 3 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 src/mrb_machine_impl/mrb_machine_adc_impl.c diff --git a/CMakeLists.txt b/CMakeLists.txt index a86315a..6073fb5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,6 +65,7 @@ set(TARGET_SOURCES "src/app_aux_ctrl.c" "src/app_mrb_repl.c" "src/app_syscalls.c" + "src/mrb_machine_impl/mrb_machine_adc_impl.c" "src/mrb_machine_impl/mrb_machine_gpio_impl.c" "src/main.c" ) diff --git a/lib/mruby b/lib/mruby index 12b520e..7f0aca0 160000 --- a/lib/mruby +++ b/lib/mruby @@ -1 +1 @@ -Subproject commit 12b520e7873432d7135f9de86330c000f8464873 +Subproject commit 7f0aca015ec2bcad7d08d912163f135bdb238149 diff --git a/src/mrb_machine_impl/mrb_machine_adc_impl.c b/src/mrb_machine_impl/mrb_machine_adc_impl.c new file mode 100644 index 0000000..bebcbf3 --- /dev/null +++ b/src/mrb_machine_impl/mrb_machine_adc_impl.c @@ -0,0 +1,127 @@ +#include + +/* Board */ +#include "board.h" + +/* SDK drivers */ +#include "fsl_anactrl.h" +#include "fsl_clock.h" +#include "fsl_gpio.h" +#include "fsl_iocon.h" +#include "fsl_lpadc.h" +#include "fsl_power.h" + +/* FreeRTOS */ +#include "FreeRTOS.h" +#include "semphr.h" + +/* Gem private */ +#include "machine-adc/src/adc.h" + +#define ADC_IMPL_PORT(x) (x / 32) +#define ADC_IMPL_PIN(x) (x % 32) + +#define ADC_EXT_CHANNEL_COUNT 10 +#define ADC_TEMP_CHANNEL 26 + +/* CH0A, CH0B, CH1A, CH1B, ... CH4A, CH4B */ +const static uint32_t s_adc_pin_table[ADC_EXT_CHANNEL_COUNT] = { + 23, 16, 10, 11, 15, 12, 31, 32, 40, 41, +}; + +static bool s_adc_initialized = false; +static SemaphoreHandle_t s_adc_semaphore = NULL; + +static void mrb_machine_adc_impl_init_peripheral(void) { + CLOCK_SetClkDiv(kCLOCK_DivAdcAsyncClk, 8, true); + CLOCK_AttachClk(kMAIN_CLK_to_ADC_CLK); + + POWER_DisablePD(kPDRUNCFG_PD_LDOGPADC); + + ANACTRL_Init(ANACTRL); + ANACTRL_EnableVref1V(ANACTRL, true); + + lpadc_config_t adc_cfg; + LPADC_GetDefaultConfig(&adc_cfg); + + adc_cfg.enableAnalogPreliminary = true; + adc_cfg.referenceVoltageSource = kLPADC_ReferenceVoltageAlt2; + adc_cfg.conversionAverageMode = kLPADC_ConversionAverage128; + + LPADC_Init(ADC0, &adc_cfg); + LPADC_DoOffsetCalibration(ADC0); + LPADC_DoAutoCalibration(ADC0); +} + +int mrb_machine_adc_impl_config(uint32_t pin) { + if (!s_adc_initialized) { + mrb_machine_adc_impl_init_peripheral(); + + s_adc_semaphore = xSemaphoreCreateBinary(); + if (s_adc_semaphore == NULL) { + return -1; + } + + s_adc_initialized = true; + } + + uint32_t iocon_mode = IOCON_PIO_ASW(1); + + /* Configure IOCON only if this is an external channel */ + if (pin < ADC_EXT_CHANNEL_COUNT) { + IOCON_PinMuxSet(IOCON, ADC_IMPL_PORT(s_adc_pin_table[pin]), ADC_IMPL_PIN(s_adc_pin_table[pin]), iocon_mode); + } + + return 0; +} + +int mrb_machine_adc_impl_read(uint32_t pin) { + lpadc_conv_command_config_t conv_cfg; + lpadc_conv_trigger_config_t trig_cfg; + + LPADC_GetDefaultConvCommandConfig(&conv_cfg); + LPADC_GetDefaultConvTriggerConfig(&trig_cfg); + + conv_cfg.conversionResolutionMode = kLPADC_ConversionResolutionHigh; + + if (pin < ADC_EXT_CHANNEL_COUNT) { + /* This is an external channel, Positive and negative pair shares the same channel */ + + lpadc_sample_channel_mode_t mode; + if ((pin % 2) == 0) { + mode = kLPADC_SampleChannelSingleEndSideA; + } else { + mode = kLPADC_SampleChannelSingleEndSideB; + } + + conv_cfg.channelNumber = pin / 2; + conv_cfg.sampleChannelMode = mode; + } else if (pin == ADC_TEMP_CHANNEL) { /* Temperature channel requires differential sampling */ + conv_cfg.channelNumber = pin; + conv_cfg.sampleChannelMode = kLPADC_SampleChannelDiffBothSide; + } else { /* Other internal channels */ + conv_cfg.channelNumber = pin; + conv_cfg.sampleChannelMode = kLPADC_SampleChannelSingleEndSideA; + } + + trig_cfg.targetCommandId = 15; + trig_cfg.enableHardwareTrigger = false; + + LPADC_SetConvCommandConfig(ADC0, 15, &conv_cfg); + LPADC_SetConvTriggerConfig(ADC0, 0U, &trig_cfg); + + LPADC_EnableInterrupts(ADC0, kLPADC_FIFO0WatermarkInterruptEnable); + EnableIRQ(ADC0_IRQn); + + return 0; +} + +void ADC0_IRQHandler(void) { + BaseType_t higher_priority_woken = pdFALSE; + + xSemaphoreGiveFromISR(s_adc_semaphore, &higher_priority_woken); + + if (higher_priority_woken) { + portYIELD_FROM_ISR(higher_priority_woken); + } +} \ No newline at end of file