hc32f460: Add support for hc32f460 micro-controllers
Signed-off-by: Steven Gotthardt <gotthardt@gmail.com>
This commit is contained in:
committed by
Kevin O'Connor
parent
94cbf5ff48
commit
72b6bd7efa
155
src/hc32f460/adc.c
Normal file
155
src/hc32f460/adc.c
Normal file
@@ -0,0 +1,155 @@
|
||||
// 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);
|
||||
Reference in New Issue
Block a user