Implemented ADC gem.
Signed-off-by: Yilin Sun <imi415@imi.moe>
This commit is contained in:
parent
a2eb84f757
commit
f6659c7958
10
README.md
10
README.md
|
@ -3,9 +3,9 @@
|
|||
## Implemented features:
|
||||
```ruby
|
||||
# Initialization: Takes a hash with configuration.
|
||||
led_red = Machine::GPIO.new({pin: 38, mode: Machine::GPIO::OUTPUT_OD, init: Machine::GPIO::ON})
|
||||
led_blue = Machine::GPIO.new({pin: 36, mode: Machine::GPIO::OUTPUT_OD, init: Machine::GPIO::ON})
|
||||
led_green = Machine::GPIO.new({pin: 39, mode: Machine::GPIO::OUTPUT_OD, init: Machine::GPIO::ON})
|
||||
led_red = Machine::GPIO.new(38, {mode: Machine::GPIO::OUTPUT_OD, init: Machine::GPIO::ON})
|
||||
led_blue = Machine::GPIO.new(36, {mode: Machine::GPIO::OUTPUT_OD, init: Machine::GPIO::ON})
|
||||
led_green = Machine::GPIO.new(39, {mode: Machine::GPIO::OUTPUT_OD, init: Machine::GPIO::ON})
|
||||
```
|
||||
|
||||
```ruby
|
||||
|
@ -16,3 +16,7 @@ led_red.on # Turn off the LED (Level is reversed)
|
|||
led_red.toggle # Toggle output
|
||||
```
|
||||
|
||||
```ruby
|
||||
ana_bg = Machine::ADC.new(52) # BandGap
|
||||
ana_bg.value
|
||||
```
|
|
@ -1 +1 @@
|
|||
Subproject commit 7f0aca015ec2bcad7d08d912163f135bdb238149
|
||||
Subproject commit 6be5185d38c88b22a9681f4937d47d568651ab73
|
|
@ -18,15 +18,39 @@
|
|||
/* Gem private */
|
||||
#include "machine-adc/src/adc.h"
|
||||
|
||||
#define ADC_IMPL_CHANNEL_ID(x) (x / 4)
|
||||
#define ADC_IMPL_CHANNEL_MODE(x) (x % 4) /* */
|
||||
#define ADC_IMPL_CHANNEL_REQUIRE_A(x) (((x % 4) != 1) ? true : false)
|
||||
#define ADC_IMPL_CHANNEL_REQUIRE_B(x) (((x % 4) != 0) ? true : false)
|
||||
|
||||
#define ADC_IMPL_VREF_UV 3300000
|
||||
#define ADC_IMPL_FULL_SCALE 65536
|
||||
#define ADC_IMPL_FULL_SCALE_DIFF (ADC_IMPL_FULL_SCALE / 2)
|
||||
|
||||
#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
|
||||
#define ADC_EXT_CHANNEL_COUNT 5
|
||||
|
||||
/**
|
||||
* Channel Allocation
|
||||
* 0, 1, 2, 3: CH0A, CH0B, CH0DIFF, CH0AB(Not supported)
|
||||
* 4, 5, 6, 7: CH1A, CH1B, CH1DIFF, CH1AB(Not supported)
|
||||
* 8, 9, 10, 11: CH2A, CH2B, CH2DIFF, CH2AB(Not supported)
|
||||
* 12, 13, 14, 15: CH3A, CH3B, CH3DIFF, CH3AB(Not supported)
|
||||
* 16, 17, 18, 19: CH4A, CH4B, CH4DIFF, CH4AB(Not supported)
|
||||
* 48: VDDA
|
||||
* 52: BIAS_VREF_1V
|
||||
* 106: TEMP_SENSOR
|
||||
*/
|
||||
|
||||
/* 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,
|
||||
const static uint32_t s_adc_pin_table_a[ADC_EXT_CHANNEL_COUNT] = {
|
||||
23, 10, 15, 31, 40,
|
||||
};
|
||||
|
||||
const static uint32_t s_adc_pin_table_b[ADC_EXT_CHANNEL_COUNT] = {
|
||||
16, 11, 12, 32, 41,
|
||||
};
|
||||
|
||||
static bool s_adc_initialized = false;
|
||||
|
@ -51,9 +75,11 @@ static void mrb_machine_adc_impl_init_peripheral(void) {
|
|||
LPADC_Init(ADC0, &adc_cfg);
|
||||
LPADC_DoOffsetCalibration(ADC0);
|
||||
LPADC_DoAutoCalibration(ADC0);
|
||||
|
||||
NVIC_SetPriority(ADC0_IRQn, 5);
|
||||
}
|
||||
|
||||
int mrb_machine_adc_impl_config(uint32_t pin) {
|
||||
int mrb_machine_adc_impl_config(uint32_t channel) {
|
||||
if (!s_adc_initialized) {
|
||||
mrb_machine_adc_impl_init_peripheral();
|
||||
|
||||
|
@ -68,14 +94,28 @@ int mrb_machine_adc_impl_config(uint32_t pin) {
|
|||
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);
|
||||
}
|
||||
if (ADC_IMPL_CHANNEL_ID(channel) < ADC_EXT_CHANNEL_COUNT) {
|
||||
uint32_t iocon_port;
|
||||
uint32_t iocon_pin;
|
||||
|
||||
if (ADC_IMPL_CHANNEL_REQUIRE_A(channel)) {
|
||||
iocon_port = ADC_IMPL_PORT(s_adc_pin_table_a[ADC_IMPL_CHANNEL_ID(channel)]);
|
||||
iocon_pin = ADC_IMPL_PIN(s_adc_pin_table_a[ADC_IMPL_CHANNEL_ID(channel)]);
|
||||
|
||||
IOCON_PinMuxSet(IOCON, iocon_port, iocon_pin, iocon_mode);
|
||||
}
|
||||
|
||||
if (ADC_IMPL_CHANNEL_REQUIRE_B(channel)) {
|
||||
iocon_port = ADC_IMPL_PORT(s_adc_pin_table_b[ADC_IMPL_CHANNEL_ID(channel)]);
|
||||
iocon_pin = ADC_IMPL_PIN(s_adc_pin_table_b[ADC_IMPL_CHANNEL_ID(channel)]);
|
||||
|
||||
IOCON_PinMuxSet(IOCON, iocon_port, iocon_pin, iocon_mode);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mrb_machine_adc_impl_read(uint32_t pin) {
|
||||
int mrb_machine_adc_impl_read(uint32_t channel) {
|
||||
lpadc_conv_command_config_t conv_cfg;
|
||||
lpadc_conv_trigger_config_t trig_cfg;
|
||||
|
||||
|
@ -84,41 +124,53 @@ int mrb_machine_adc_impl_read(uint32_t pin) {
|
|||
|
||||
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;
|
||||
}
|
||||
conv_cfg.channelNumber = ADC_IMPL_CHANNEL_ID(channel);
|
||||
conv_cfg.sampleChannelMode = ADC_IMPL_CHANNEL_MODE(channel);
|
||||
|
||||
trig_cfg.targetCommandId = 15;
|
||||
trig_cfg.enableHardwareTrigger = false;
|
||||
trig_cfg.channelAFIFOSelect = 0U;
|
||||
trig_cfg.channelBFIFOSelect = 0U;
|
||||
|
||||
LPADC_SetConvCommandConfig(ADC0, 15, &conv_cfg);
|
||||
LPADC_SetConvTriggerConfig(ADC0, 0U, &trig_cfg);
|
||||
|
||||
/* Wait for 2 data if 2 channels are being sampled. */
|
||||
if (ADC_IMPL_CHANNEL_MODE(channel) == kLPADC_SampleChannelDualSingleEndBothSide) {
|
||||
ADC0->FCTRL[0] = ADC_FCTRL_FWMARK(1);
|
||||
} else {
|
||||
ADC0->FCTRL[0] = ADC_FCTRL_FWMARK(0);
|
||||
}
|
||||
|
||||
LPADC_EnableInterrupts(ADC0, kLPADC_FIFO0WatermarkInterruptEnable);
|
||||
EnableIRQ(ADC0_IRQn);
|
||||
|
||||
return 0;
|
||||
LPADC_DoSoftwareTrigger(ADC0, 1U);
|
||||
|
||||
if (xSemaphoreTake(s_adc_semaphore, pdMS_TO_TICKS(500)) != pdTRUE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t result_count = LPADC_GetConvResultCount(ADC0, 0);
|
||||
|
||||
lpadc_conv_result_t rslt;
|
||||
|
||||
for (uint8_t i = 0; i < result_count; i++) {
|
||||
LPADC_GetConvResult(ADC0, &rslt, 0);
|
||||
}
|
||||
|
||||
if (ADC_IMPL_CHANNEL_MODE(channel) == kLPADC_SampleChannelDiffBothSide) {
|
||||
return (int)((int64_t)(int16_t)rslt.convValue * ADC_IMPL_VREF_UV / ADC_IMPL_FULL_SCALE_DIFF);
|
||||
}
|
||||
|
||||
return (int)((int64_t)rslt.convValue * ADC_IMPL_VREF_UV / ADC_IMPL_FULL_SCALE);
|
||||
}
|
||||
|
||||
void ADC0_IRQHandler(void) {
|
||||
BaseType_t higher_priority_woken = pdFALSE;
|
||||
|
||||
DisableIRQ(ADC0_IRQn);
|
||||
|
||||
xSemaphoreGiveFromISR(s_adc_semaphore, &higher_priority_woken);
|
||||
|
||||
if (higher_priority_woken) {
|
||||
|
|
Loading…
Reference in New Issue