Skip to content

Core api update analog io #352

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Jun 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions ci-matrix-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,18 @@ sketch:
- extras/arduino-examples/examples/01.Basics/BareMinimum/BareMinimum.ino
- extras/arduino-examples/examples/01.Basics/Blink/Blink.ino
- extras/arduino-examples/examples/01.Basics/DigitalReadSerial/DigitalReadSerial.ino
- extras/arduino-examples/examples/01.Basics/AnalogReadSerial/AnalogReadSerial.ino
- extras/arduino-examples/examples/01.Basics/Fade/Fade.ino
- extras/arduino-examples/examples/02.Digital/BlinkWithoutDelay/BlinkWithoutDelay.ino
- extras/arduino-examples/examples/02.Digital/Button/Button.ino
- extras/arduino-examples/examples/02.Digital/Debounce/Debounce.ino
- extras/arduino-examples/examples/02.Digital/DigitalInputPullup/DigitalInputPullup.ino
- extras/arduino-examples/examples/02.Digital/StateChangeDetection/StateChangeDetection.ino
- extras/arduino-examples/examples/03.Analog/AnalogInOutSerial/AnalogInOutSerial.ino
- extras/arduino-examples/examples/03.Analog/AnalogInput/AnalogInput.ino
- extras/arduino-examples/examples/03.Analog/Calibration/Calibration.ino
- extras/arduino-examples/examples/03.Analog/Fading/Fading.ino
- extras/arduino-examples/examples/03.Analog/Smoothing/Smoothing.ino
- extras/arduino-examples/examples/04.Communication/ASCIITable/ASCIITable.ino
- extras/arduino-examples/examples/04.Communication/MultiSerial/MultiSerial.ino
- extras/arduino-examples/examples/04.Communication/PhysicalPixel/PhysicalPixel.ino
Expand Down
21 changes: 17 additions & 4 deletions cores/xmc/Arduino.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ extern "C" {
#define interrupts() __enable_irq()
#define noInterrupts() __disable_irq()

#define DEFAULT XMC_VADC_CHANNEL_REF_INTREF /*< Default ADC reference voltage type */

//****************************************************************************
// @Typedefs
//****************************************************************************
Expand Down Expand Up @@ -321,14 +323,25 @@ extern void setup(void);
*/
extern void loop(void);

/*
* \brief Set the resolution of analogRead return values. Default is 10 bits (range from 0 to 1023).
*
* \param res
*/
extern void analogReadResolution(int res);

/*
* \brief Set the resolution of analogWrite parameters. Default is 8 bits (range from 0 to 255).
*
* \param res
*/
extern void analogWriteResolution(int res);
//****************************************************************************
// @Arduino Core Includes
//****************************************************************************
#include "wiring_time.h"
// #include "wiring_digital.h"
/*
#include "wiring_analog.h"
#include "wiring_shift.h"

/*#include "wiring_shift.h"
#include "wiring_pulse.h"

#include "WInterrupts.h"
Expand Down
1 change: 0 additions & 1 deletion cores/xmc/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ int main(void) {
* Initialization Time first to get closer to startup time accuracy
*/
wiring_time_init();
// wiring_analog_init();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is no longer called anywhere?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is called in analogRead(), since it only initialize ADC


// Initialize the reset pin for the XMC1100 Boot Kit series and XMC1400 Kit for Arduino as they are
// based on Arduino form-factor Hence, a dedicated reset pin is required.
Expand Down
282 changes: 282 additions & 0 deletions cores/xmc/wiring_analog.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,282 @@
//****************************************************************************
// @File: wiring_analog.cpp
// @Brief: Analog and PWM/DAC API implementation for XMC Arduino core
//****************************************************************************
#include "Arduino.h"

//****************************************************************************
// @Defines
//****************************************************************************
#define ADC_CONVERSION_GROUP 0
#define ADC_MIN_RESOLUTION 8
#define ADC_MAX_READ_RESOLUTION 12
#define ANALOG_MAX_WRITE_RESOLUTION 16

//****************************************************************************
// @Global Variables
//****************************************************************************
static XMC_VADC_CHANNEL_REF_t analog_reference = DEFAULT;
static uint8_t _readResolution = 10;
static uint8_t _writeResolution = 8;
uint16_t _readMaximum = 1023;
uint16_t _writeMaximum = 255;
static bool vadc_inited = false;

//****************************************************************************
// @Function: scan_map_table
// @Brief: Lookup table for pin to resource mapping
//****************************************************************************
int16_t scan_map_table(const uint8_t table[][2], uint8_t pin) {
int16_t i = 0;
while (table[i][0] != 255) {
if (table[i][0] == pin)
break;
i++;
}
if (table[i][0] != 255)
return table[i][1];
return -1;
}

//****************************************************************************
// @Function: analogReference
// @Brief: Sets the ADC reference voltage type. Only default (Varef = Vdda) is available.
//****************************************************************************
void analogReference(uint8_t mode) {
switch (mode) {
case DEFAULT:
analog_reference = XMC_VADC_CHANNEL_REF_INTREF;
break;
default:
// Invalid mode, do nothing
break;
}
}

//****************************************************************************
// @Function: analogWriteResolution
// @Brief: Sets the resolution for analogWrite (PWM/DAC)
//****************************************************************************
void analogWriteResolution(int res) {
if (res > ANALOG_MAX_WRITE_RESOLUTION) {
_writeResolution = ANALOG_MAX_WRITE_RESOLUTION;
} else if (res < ADC_MIN_RESOLUTION) {
_writeResolution = ADC_MIN_RESOLUTION;
} else {
_writeResolution = res;
}
_writeMaximum = (uint16_t)(((uint32_t)1U << _writeResolution) - 1);
}

//****************************************************************************
// @Function: analogWrite
// @Brief: Outputs PWM or DAC value to the specified pin
//****************************************************************************
void analogWrite(pin_size_t pinNumber, int value) {
uint32_t compare_reg = 0;
int16_t resource;
if (value < 0 || value > _writeMaximum)
return;
// Check if the pin supports PWM4
resource = scan_map_table(mapping_pin_PWM4, pinNumber);
if (resource >= 0) {
XMC_PWM4_t *pwm4 = &mapping_pwm4[resource];
if (!(pwm4->enabled)) {
// Slice not yet initialized
XMC_CCU4_SLICE_COMPARE_CONFIG_t pwm_config;
memset(&pwm_config, 0, sizeof(XMC_CCU4_SLICE_COMPARE_CONFIG_t));
pwm_config.passive_level = XMC_CCU4_SLICE_OUTPUT_PASSIVE_LEVEL_HIGH;
pwm_config.prescaler_initval = pwm4->prescaler;
XMC_CCU4_Init(pwm4->ccu, XMC_CCU4_SLICE_MCMS_ACTION_TRANSFER_PR_CR);
XMC_CCU4_SLICE_CompareInit(pwm4->slice, &pwm_config);
XMC_CCU4_EnableClock(pwm4->ccu, pwm4->slice_num);
XMC_CCU4_SLICE_SetTimerPeriodMatch(pwm4->slice, pwm4->period_timer_val);
pwm4->enabled = true;
}
if (value != 0)
compare_reg = ((value + 1) * (pwm4->period_timer_val + 1)) >> _writeResolution;
XMC_CCU4_SLICE_SetTimerCompareMatch(pwm4->slice, compare_reg);
XMC_CCU4_EnableShadowTransfer(pwm4->ccu, (CCU4_GCSS_S0SE_Msk << (4 * pwm4->slice_num)));
XMC_GPIO_SetMode(pwm4->port_pin.port, pwm4->port_pin.pin,
(XMC_GPIO_MODE_t)(XMC_GPIO_MODE_OUTPUT_PUSH_PULL | pwm4->port_mode));
XMC_CCU4_SLICE_StartTimer(pwm4->slice);

return;
}
#if defined(CCU8V2) || defined(CCU8V1)
// Check if the pin supports PWM8
else if ((resource = scan_map_table(mapping_pin_PWM8, pinNumber)) >= 0) {
XMC_PWM8_t *pwm8 = &mapping_pwm8[resource];
if (!(pwm8->enabled)) {
// Slice not yet initialized
XMC_CCU8_SLICE_COMPARE_CONFIG_t pwm_config;
memset(&pwm_config, 0, sizeof(XMC_CCU8_SLICE_COMPARE_CONFIG_t));
pwm_config.passive_level_out0 = XMC_CCU8_SLICE_OUTPUT_PASSIVE_LEVEL_HIGH;
pwm_config.passive_level_out1 = XMC_CCU8_SLICE_OUTPUT_PASSIVE_LEVEL_HIGH;
pwm_config.passive_level_out2 = XMC_CCU8_SLICE_OUTPUT_PASSIVE_LEVEL_HIGH;
pwm_config.passive_level_out3 = XMC_CCU8_SLICE_OUTPUT_PASSIVE_LEVEL_HIGH;
pwm_config.prescaler_initval = pwm8->prescaler;
XMC_CCU8_Init(pwm8->ccu, XMC_CCU8_SLICE_MCMS_ACTION_TRANSFER_PR_CR);
XMC_CCU8_SLICE_CompareInit(pwm8->slice, &pwm_config);
XMC_CCU8_EnableClock(pwm8->ccu, pwm8->slice_num);
XMC_CCU8_SLICE_SetTimerPeriodMatch(pwm8->slice, pwm8->period_timer_val);
pwm8->enabled = true;
}
if (value != 0)
compare_reg = ((value + 1) * (pwm8->period_timer_val + 1)) >> _writeResolution;
XMC_CCU8_SLICE_SetTimerCompareMatch(pwm8->slice, pwm8->slice_channel, compare_reg);
XMC_CCU8_EnableShadowTransfer(pwm8->ccu, CCU8_GCSS_S0SE_Msk << (4 * pwm8->slice_num));
XMC_GPIO_SetMode(pwm8->port_pin.port, pwm8->port_pin.pin,
(XMC_GPIO_MODE_t)(XMC_GPIO_MODE_OUTPUT_PUSH_PULL | pwm8->port_mode));
XMC_CCU8_SLICE_StartTimer(pwm8->slice);
return;
}
#endif
#ifdef DAC
// Check if the pin supports DAC
else if ((resource = scan_map_table(mapping_pin_DAC, pinNumber)) >= 0) {
XMC_ARD_DAC_t *dac = &(mapping_dac[resource]);
XMC_DAC_Enable(dac->group);
XMC_DAC_CH_EnableOutput(dac->group, dac->channel);
XMC_DAC_CH_StartSingleValueMode(dac->group, dac->channel);
uint16_t dacValue =
map(value, 0, (0b10 << _writeResolution) - 1, 0, (0b10 << dac->resolution) - 1);
XMC_DAC_CH_Write(dac->group, dac->channel, dacValue);
return;
}
#endif
// If not found, do nothing
return;
}

//****************************************************************************
// @Function: wiring_analog_init
// @Brief: Initializes VADC and related analog resources (runs only once)
//****************************************************************************
void wiring_analog_init(void) {
if (vadc_inited)
return;
vadc_inited = true;
/* Initialization data of VADC Global resources */
XMC_VADC_GLOBAL_CONFIG_t vadc_global_config;
memset(&vadc_global_config, 0, sizeof(XMC_VADC_GLOBAL_CONFIG_t));
vadc_global_config.class0.conversion_mode_standard = XMC_VADC_CONVMODE_12BIT;
vadc_global_config.class1.conversion_mode_standard = XMC_VADC_CONVMODE_12BIT;

XMC_VADC_BACKGROUND_CONFIG_t vadc_background_config = {0};

/* Provide clock to VADC and initialize the VADC global registers. */
XMC_VADC_GLOBAL_Init(VADC, &vadc_global_config);

#if (XMC_VADC_GROUP_AVAILABLE == 1U)
// ADC grouping
XMC_VADC_GROUP_CONFIG_t vadc_group_config;
memset(&vadc_group_config, 0, sizeof(XMC_VADC_GROUP_CONFIG_t));
vadc_group_config.class0.conversion_mode_standard = XMC_VADC_CONVMODE_12BIT;
vadc_group_config.class1.conversion_mode_standard = XMC_VADC_CONVMODE_12BIT;

/* Initialize Group */
XMC_VADC_GROUP_Init(VADC_G0, &vadc_group_config);
XMC_VADC_GROUP_Init(VADC_G1, &vadc_group_config);

/* Switch on the converter of the Group*/
XMC_VADC_GROUP_SetPowerMode(VADC_G0, XMC_VADC_GROUP_POWERMODE_NORMAL);
XMC_VADC_GROUP_SetPowerMode(VADC_G1, XMC_VADC_GROUP_POWERMODE_NORMAL);

#if (XMC_VADC_MAXIMUM_NUM_GROUPS > 2)
/* Initialize Group */
XMC_VADC_GROUP_Init(VADC_G2, &vadc_group_config);
XMC_VADC_GROUP_Init(VADC_G3, &vadc_group_config);

/* Switch on the converter of the Group*/
XMC_VADC_GROUP_SetPowerMode(VADC_G2, XMC_VADC_GROUP_POWERMODE_NORMAL);
XMC_VADC_GROUP_SetPowerMode(VADC_G3, XMC_VADC_GROUP_POWERMODE_NORMAL);
#endif

#endif
/* Calibrate the VADC. Make sure you do this after all used VADC groups
are set to normal operation mode. */
XMC_VADC_GLOBAL_StartupCalibration(VADC);

/* Initialize the background source hardware. The gating mode is set to
ignore to pass external triggers unconditionally.*/
XMC_VADC_GLOBAL_BackgroundInit(VADC, &vadc_background_config);

/* Dummy read of ALL analogue inputs to ensure ALL analogue channels are
started in background scanning mode, otherwise first readings at least
will always be zero on reading an analogue input. */
for (uint8_t chan = 0; chan < NUM_ANALOG_INPUTS; chan++)
analogRead(chan);

// Additional Initialization of DAC starting here
}

//****************************************************************************
// @Function: analogReadResolution
// @Brief: Sets the resolution for analogRead (ADC)
//****************************************************************************
void analogReadResolution(int res) {
if (res > ADC_MAX_READ_RESOLUTION) {
_readResolution = ADC_MAX_READ_RESOLUTION;
} else if (res < ADC_MIN_RESOLUTION) {
_readResolution = ADC_MIN_RESOLUTION;
} else {
_readResolution = res;
}
_readMaximum = (uint16_t)(((uint32_t)1U << _readResolution) - 1);
}

//****************************************************************************
// @Function: analogRead
// @Brief: Reads the analog value from the specified pin
//****************************************************************************
int analogRead(pin_size_t pinNumber) {

wiring_analog_init();
uint32_t value;

value = 0xFFFFFFFF;
if (pinNumber < NUM_ANALOG_INPUTS) {
Copy link
Preview

Copilot AI Jun 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pinNumber here is the Arduino pin index (e.g., A0 = 14), but it’s being used directly as an index into mapping_adc. You need a lookup (e.g., using scan_map_table) to map Arduino pin numbers to ADC channel entries.

Copilot uses AI. Check for mistakes.

XMC_ADC_t *adc = &mapping_adc[pinNumber];

#if (XMC_VADC_GROUP_AVAILABLE == 1U)
// ADC grouping
if (!(adc->enabled)) {
XMC_VADC_CHANNEL_CONFIG_t vadc_gobal_channel_config;
memset(&vadc_gobal_channel_config, 0, sizeof(XMC_VADC_CHANNEL_CONFIG_t));
vadc_gobal_channel_config.input_class = XMC_VADC_CHANNEL_CONV_GROUP_CLASS1;
vadc_gobal_channel_config.result_reg_number = adc->result_reg_num;
vadc_gobal_channel_config.alias_channel = XMC_VADC_CHANNEL_ALIAS_DISABLED;

XMC_VADC_RESULT_CONFIG_t vadc_gobal_result_config = {.g_rcr = 0};
/* Configure a channel belonging to the aforesaid conversion kernel */
XMC_VADC_GROUP_ChannelInit(adc->group, adc->channel_num, &vadc_gobal_channel_config);
/* Configure a result resource belonging to the aforesaid conversion kernel */
XMC_VADC_GROUP_ResultInit(adc->group, adc->result_reg_num, &vadc_gobal_result_config);
/* Add channel into the Background Request Source Channel Select Register */
XMC_VADC_GLOBAL_BackgroundAddChannelToSequence(VADC, (uint32_t)adc->group_num,
(uint32_t)adc->channel_num);
}
/* Start conversion manually using load event trigger*/
XMC_VADC_GLOBAL_BackgroundTriggerConversion(VADC);
value = XMC_VADC_GROUP_GetResult(adc->group, adc->result_reg_num);
#else
// XMC1100 no ADC grouping
if (!(adc->enabled))
/* Add a channel to the background source. */
VADC->BRSSEL[ADC_CONVERSION_GROUP] = (uint32_t)(1U << adc->channel_num);
// Generates conversion request
XMC_VADC_GLOBAL_BackgroundTriggerConversion(VADC);

// Wait until conversion is ready
while (((value = XMC_VADC_GLOBAL_GetDetailedResult(VADC)) & VADC_GLOBRES_VF_Msk) == 0u)
;
#endif
value = ((value & VADC_GLOBRES_RESULT_Msk) >> (ADC_MAX_READ_RESOLUTION - _readResolution));
}
return value;
}

//****************************************************************************
// END OF FILE
//****************************************************************************
Loading
Loading