Steven Gotthardt 72b6bd7efa hc32f460: Add support for hc32f460 micro-controllers
Signed-off-by: Steven Gotthardt <gotthardt@gmail.com>
2023-02-13 12:12:27 -05:00

156 lines
4.0 KiB
C

// ADC functions on Huada HC32F460
//
// Copyright (C) 2022 Steven Gotthardt <gotthardt@gmail.com>
//
// This file may be distributed under the terms of the GNU GPLv3 license.
#include "generic/misc.h" // timer_from_us
#include "command.h" // shutdown
#include "board/gpio.h" // gpio_adc_setup
#include "board/internal.h" // GPIO
#include "sched.h" // sched_shutdown
// library
#include "hc32f460_adc.h"
#include "hc32f460_pwc.h"
#include "hc32f460_gpio.h"
#define ADC_RESOLUTION_12BIT (12u)
#define ADC_RESOLUTION_10BIT (10u)
#define ADC_RESOLUTION_8BIT (8u)
#define ADC1_RESOLUTION (ADC_RESOLUTION_12BIT)
#define ADC1_PRECISION (1ul << ADC1_RESOLUTION)
#if ADC1_RESOLUTION == ADC_RESOLUTION_12BIT
#define AdcResolution AdcResolution_12Bit
#elif ADC1_RESOLUTION == ADC_RESOLUTION_10BIT
#define AdcResolution AdcResolution_10Bit
#else
#define AdcResolution AdcResolution_8Bit
#endif
/* Timeout value definitions. Found in example code */
#define TIMEOUT_VAL (30u)
DECL_CONSTANT("ADC_MAX", ADC1_PRECISION-1);
// These pins can be used for ADC
static const uint8_t adc_gpio[] = {
GPIO('A', 0), // Chan 0
GPIO('A', 1), // Chan 1
GPIO('A', 2), // Chan 2
GPIO('A', 3), // Chan 3
GPIO('A', 4), // Chan 4
GPIO('A', 5), // Chan 5
GPIO('A', 6), // Chan 6
GPIO('A', 7), // Chan 7
GPIO('B', 0), // Chan 8
GPIO('B', 1), // Chan 9
GPIO('C', 0), // Chan 10 // TBed on TriGorilla
GPIO('C', 1), // Chan 11 // THead on TriGorilla
GPIO('C', 2), // Chan 12
GPIO('C', 3), // Chan 13
GPIO('C', 4), // Chan 14 // TBed on aquilla
GPIO('C', 5), // Chan 15 // THead on aquilla
};
struct gpio_adc
gpio_adc_setup(uint32_t gpio)
{
// validate pin in adc_pins table
int chan;
for (chan=0; ; chan++)
{
if (chan >= ARRAY_SIZE(adc_gpio))
{
shutdown("Not a valid ADC pin");
}
if (adc_gpio[chan] == gpio)
{
break;
}
}
// set as analog
gpio_peripheral(gpio, Pin_Mode_Ana, 0);
uint8_t sampleTime[ARRAY_SIZE(adc_gpio)] = { TIMEOUT_VAL }; // all chans
stc_adc_ch_cfg_t stcAdcChan;
stcAdcChan.u32Channel = 1 << chan;
stcAdcChan.u8Sequence = ADC_SEQ_A; // all conversions are in SEQ A
stcAdcChan.pu8SampTime = sampleTime;
ADC_AddAdcChannel(M4_ADC1, &stcAdcChan);
return (struct gpio_adc){ .chan = chan };
}
// Try to sample a value. Returns zero if sample ready, otherwise
// returns the number of clock ticks the caller should wait before
// retrying this function.
uint32_t
gpio_adc_sample(struct gpio_adc g)
{
// true if the sequence is finished
if (ADC_GetEocFlag(M4_ADC1, ADC_SEQ_A))
{
// all conversions are done - clear the flag
ADC_ClrEocFlag(M4_ADC1, ADC_SEQ_A);
return 0;
}
else if (M4_ADC1->STR & 1)
{
// running but not done yet
return timer_from_us(TIMEOUT_VAL/2);
}
else
{
// not running - so start
ADC_StartConvert(M4_ADC1);
}
return timer_from_us(TIMEOUT_VAL);
}
// Read a value; use only after gpio_adc_sample() returns zero
uint16_t
gpio_adc_read(struct gpio_adc g)
{
// return the one we want...
return ADC_GetValue(M4_ADC1, g.chan);
}
// Cancel a sample that may have been started with gpio_adc_sample()
void
gpio_adc_cancel_sample(struct gpio_adc g)
{
ADC_StopConvert(M4_ADC1);
}
// The clocks are already set by the loader.
// There is ADC1 and ADC2. Sequences do all channels at once.
void
adc_init(void)
{
// PCLK2 (ADC clock) is 'divide by 4', Max ADC clock is 60MHz
stc_adc_init_t stcAdcInit = {0};
stcAdcInit.enResolution = AdcResolution; // see define above
stcAdcInit.enDataAlign = AdcDataAlign_Right;
stcAdcInit.enAutoClear = AdcClren_Disable;
stcAdcInit.enScanMode = AdcMode_SAOnce;
// power-on ADC
PWC_Fcg3PeriphClockCmd(PWC_FCG3_PERIPH_ADC1, Enable);
// only using ADC1
ADC_Init(M4_ADC1, &stcAdcInit);
}
DECL_INIT(adc_init);