Skip to content

Commit

Permalink
Release 2.3.0 (#161)
Browse files Browse the repository at this point in the history
* Give friendly error message in BLE examples when wrong stack is selected

Instead of cryptic errors users will get a clear message.

* Add BLE HID mouse example

(supported on xG24 DevKit, xG27 DevKit)

* Implement analog microphone driver

* Improvements for the ADC and analog microphone driver

* add "tensorflow_lite_micro" sw component to nano matter "no_radio" variant
add SilabsTFLite library with examples

* Remove example with tensorflow lite standard library

* add missing licenses

* Uncrustify TFlite library, update copyright year

* Add the TFlite library examples to the build test

* Add Bluetooth mouse example for the XIAO MG24 Sense

* Create README.md for package folder

* Update package/README.md: add troubleshooting section

* Update readme.md

* Update generate_gsdk.py

* Update package/README.md

* generate_gsdk.py: fix gsdk.a creation for linux system

* Update README.md

* adding Tamas review changes

* Add config file for generate_gsdk.py

This makes configuring the generator script for
each user easier.

* Update gitignore with generate_gsdk.cfg

* add instructions for generate_gsdk.cfg file

* Fix config parser in generate_gsdk.py

* Add the TFLite library to the readme

* Bump the core version to 2.3.0

---------

Co-authored-by: Zoltan Fegyveres <[email protected]>
Co-authored-by: Áron Gyapjas <[email protected]>
Co-authored-by: Leonardo Cavagnis <[email protected]>
Co-authored-by: Leonardo Cavagnis <[email protected]>
  • Loading branch information
5 people authored Feb 21, 2025
1 parent b049267 commit c51e6c0
Show file tree
Hide file tree
Showing 309 changed files with 72,529 additions and 66 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
package/gen
package/gen_gsdk*
package/install_host*
package/generate_gsdk.cfg
installed.json
40 changes: 20 additions & 20 deletions boards.txt

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions cores/silabs/Arduino.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,18 @@ void analogWrite(dac_channel_t dac_channel, int value);
void analogWriteResolution(int resolution);
void analogReadResolution(int resolution);

/***************************************************************************//**
* Starts continuous ADC sample acquisition using DMA
*
* @param[in] pin The selected analog input pin
* @param[in] buffer Pointer to the sampling buffer
* @param[in] size The size of the sampling buffer
* @param[in] user_onsampling_finished_callback Callback that gets called when an
* acquisition finishes - pass 'nullptr' to stop sampling
******************************************************************************/
void analogReadDMA(PinName pin, uint32_t *buffer, uint32_t size, void (*user_onsampling_finished_callback)());
void analogReadDMA(pin_size_t pin, uint32_t *buffer, uint32_t size, void (*user_onsampling_finished_callback)());

bool get_system_init_finished();
uint32_t get_system_reset_cause();
void escape_hatch();
Expand Down
264 changes: 257 additions & 7 deletions cores/silabs/adc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,23 @@

using namespace arduino;

static bool dma_transfer_finished_cb(unsigned int channel, unsigned int sequenceNo, void *userParam);

AdcClass::AdcClass() :
initialized(false),
initialized_single(false),
initialized_scan(false),
paused_transfer(false),
current_adc_pin(PD2),
current_adc_reference(AR_VDD),
current_read_resolution(this->max_read_resolution_bits),
user_onsampling_finished_callback(nullptr),
adc_mutex(nullptr)
{
this->adc_mutex = xSemaphoreCreateMutexStatic(&this->adc_mutex_buf);
configASSERT(this->adc_mutex);
}

void AdcClass::init(PinName pin, uint8_t reference)
void AdcClass::init_single(PinName pin, uint8_t reference)
{
// Set up the ADC pin as an input
pinMode(pin, INPUT);
Expand Down Expand Up @@ -126,16 +131,180 @@ void AdcClass::init(PinName pin, uint8_t reference)
}
}

this->initialized = true;
this->initialized_scan = false;
this->initialized_single = true;
}

void AdcClass::init_scan(PinName pin, uint8_t reference)
{
// Set up the ADC pin as an input
pinMode(pin, INPUT);

// Create ADC init structs with default values
IADC_Init_t init = IADC_INIT_DEFAULT;
IADC_AllConfigs_t all_configs = IADC_ALLCONFIGS_DEFAULT;
IADC_InitScan_t init_scan = IADC_INITSCAN_DEFAULT;

// Scan table structure
IADC_ScanTable_t scanTable = IADC_SCANTABLE_DEFAULT;

// Enable IADC0, GPIO and PRS clock branches
CMU_ClockEnable(cmuClock_IADC0, true);
CMU_ClockEnable(cmuClock_GPIO, true);
CMU_ClockEnable(cmuClock_PRS, true);

// Shutdown between conversions to reduce current
init.warmup = iadcWarmupNormal;

// Set the HFSCLK prescale value here
init.srcClkPrescale = IADC_calcSrcClkPrescale(IADC0, 20000000, 0);

IADC_CfgReference_t sl_adc_reference;
uint32_t sl_adc_vref;

// Set the voltage reference
switch (reference) {
case AR_INTERNAL1V2:
sl_adc_reference = iadcCfgReferenceInt1V2;
sl_adc_vref = 1200;
break;

case AR_EXTERNAL_1V25:
sl_adc_reference = iadcCfgReferenceExt1V25;
sl_adc_vref = 1250;
break;

case AR_VDD:
sl_adc_reference = iadcCfgReferenceVddx;
sl_adc_vref = 3300;
break;

case AR_08VDD:
sl_adc_reference = iadcCfgReferenceVddX0P8Buf;
sl_adc_vref = 2640;
break;

default:
return;
}

// Set the voltage reference
all_configs.configs[0].reference = sl_adc_reference;
all_configs.configs[0].vRef = sl_adc_vref;
all_configs.configs[0].osrHighSpeed = iadcCfgOsrHighSpeed2x;
all_configs.configs[0].analogGain = iadcCfgAnalogGain1x;

/*
* CLK_SRC_ADC must be prescaled by some value greater than 1 to
* derive the intended CLK_ADC frequency.
* Based on the default 2x oversampling rate (OSRHS)...
* conversion time = ((4 * OSRHS) + 2) / fCLK_ADC
* ...which results in a maximum sampling rate of 833 ksps with the
* 2-clock input multiplexer switching time is included.
*/
all_configs.configs[0].adcClkPrescale = IADC_calcAdcClkPrescale(IADC0,
10000000,
0,
iadcCfgModeNormal,
init.srcClkPrescale);

// Reset the ADC
IADC_reset(IADC0);

// Only configure the ADC if it is not already running
if (IADC0->CTRL == _IADC_CTRL_RESETVALUE) {
IADC_init(IADC0, &init, &all_configs);
}

// Assign the input pin
uint32_t pin_index = pin - PIN_NAME_MIN;

// Trigger continuously once scan is started
init_scan.triggerAction = iadcTriggerActionContinuous;
// Set the SCANFIFODVL flag when scan FIFO holds 2 entries
// The interrupt associated with the SCANFIFODVL flag in the IADC_IF register is not used
init_scan.dataValidLevel = iadcFifoCfgDvl1;
// Enable DMA wake-up to save the results when the specified FIFO level is hit
init_scan.fifoDmaWakeup = true;

scanTable.entries[0].posInput = GPIO_to_ADC_pin_map[pin_index];
scanTable.entries[0].includeInScan = true;

// Initialize scan
IADC_initScan(IADC0, &init_scan, &scanTable);
IADC_enableInt(IADC0, IADC_IEN_SCANTABLEDONE);

// Allocate the analog bus for ADC0 inputs
// Port C and D are handled together
// Even and odd pins on the same port have a different register value
bool pin_is_even = (pin % 2 == 0);
if (pin >= PD0 || pin >= PC0) {
if (pin_is_even) {
GPIO->CDBUSALLOC |= GPIO_CDBUSALLOC_CDEVEN0_ADC0;
} else {
GPIO->CDBUSALLOC |= GPIO_CDBUSALLOC_CDODD0_ADC0;
}
} else if (pin >= PB0) {
if (pin_is_even) {
GPIO->BBUSALLOC |= GPIO_BBUSALLOC_BEVEN0_ADC0;
} else {
GPIO->BBUSALLOC |= GPIO_BBUSALLOC_BODD0_ADC0;
}
} else {
if (pin_is_even) {
GPIO->ABUSALLOC |= GPIO_ABUSALLOC_AEVEN0_ADC0;
} else {
GPIO->ABUSALLOC |= GPIO_ABUSALLOC_AODD0_ADC0;
}
}

this->initialized_single = false;
this->initialized_scan = true;
}

sl_status_t AdcClass::init_dma(uint32_t *buffer, uint32_t size)
{
sl_status_t status;
if (!this->initialized_scan) {
return SL_STATUS_NOT_INITIALIZED;
}

// Initialize DMA with default parameters
DMADRV_Init();

// Allocate DMA channel
status = DMADRV_AllocateChannel(&this->dma_channel, NULL);
if (status != ECODE_EMDRV_DMADRV_OK) {
return SL_STATUS_FAIL;
}

// Trigger LDMA transfer on IADC scan completion
LDMA_TransferCfg_t transferCfg = LDMA_TRANSFER_CFG_PERIPHERAL(ldmaPeripheralSignal_IADC0_IADC_SCAN);

/*
* Set up a linked descriptor to save scan results to the
* user-specified buffer. By linking the descriptor to itself
* (the last argument is the relative jump in terms of the number of
* descriptors), transfers will run continuously.
*/
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
this->ldma_descriptor = (LDMA_Descriptor_t)LDMA_DESCRIPTOR_LINKREL_P2M_WORD(&(IADC0->SCANFIFODATA), buffer, size, 0);

DMADRV_LdmaStartTransfer((int)this->dma_channel, &transferCfg, &this->ldma_descriptor, dma_transfer_finished_cb, NULL);
return SL_STATUS_OK;
}

uint16_t AdcClass::get_sample(PinName pin)
{
xSemaphoreTake(this->adc_mutex, portMAX_DELAY);

if (!this->initialized || pin != this->current_adc_pin) {
if (this->initialized_scan) {
this->scan_stop();
}

if (!this->initialized_single || (pin != this->current_adc_pin)) {
this->current_adc_pin = pin;
this->init(this->current_adc_pin, this->current_adc_reference);
this->init_single(this->current_adc_pin, this->current_adc_reference);
}
// Clear single done interrupt
IADC_clearInt(IADC0, IADC_IF_SINGLEDONE);
Expand All @@ -162,18 +331,99 @@ void AdcClass::set_reference(uint8_t reference)
}
xSemaphoreTake(this->adc_mutex, portMAX_DELAY);
this->current_adc_reference = reference;
this->init(this->current_adc_pin, this->current_adc_reference);
if (this->initialized_single) {
this->init_single(this->current_adc_pin, this->current_adc_reference);
} else if (this->initialized_scan) {
this->init_scan(this->current_adc_pin, this->current_adc_reference);
}
xSemaphoreGive(this->adc_mutex);
}

void AdcClass::set_read_resolution(uint8_t resolution) {
void AdcClass::set_read_resolution(uint8_t resolution)
{
if (resolution > this->max_read_resolution_bits) {
this->current_read_resolution = this->max_read_resolution_bits;
return;
}
this->current_read_resolution = resolution;
}

sl_status_t AdcClass::scan_start(PinName pin, uint32_t *buffer, uint32_t size, void (*user_onsampling_finished_callback)())
{
sl_status_t status = SL_STATUS_FAIL;
xSemaphoreTake(this->adc_mutex, portMAX_DELAY);

if ((!this->initialized_scan && !this->initialized_single) || (pin != this->current_adc_pin)) {
// Initialize in scan mode
this->current_adc_pin = pin;
this->user_onsampling_finished_callback = user_onsampling_finished_callback;
this->init_scan(this->current_adc_pin, this->current_adc_reference);
status = this->init_dma(buffer, size);
} else if (this->initialized_scan && this->paused_transfer) {
// Resume DMA transfer if paused
status = DMADRV_ResumeTransfer(this->dma_channel);
this->paused_transfer = false;
} else if (this->initialized_single) {
// Initialize in scan mode if it was initialized in single mode
this->deinit();
this->current_adc_pin = pin;
this->user_onsampling_finished_callback = user_onsampling_finished_callback;
this->init_scan(this->current_adc_pin, this->current_adc_reference);
status = this->init_dma(buffer, size);
} else {
xSemaphoreGive(this->adc_mutex);
return status;
}

// Start the conversion and wait for results
IADC_command(IADC0, iadcCmdStartScan);

xSemaphoreGive(this->adc_mutex);
return status;
}

void AdcClass::scan_stop()
{
// Pause sampling
DMADRV_PauseTransfer(this->dma_channel);
this->paused_transfer = true;
}

void AdcClass::deinit()
{
// Stop sampling
DMADRV_StopTransfer(this->dma_channel);

// Free resources
DMADRV_FreeChannel(this->dma_channel);

// Reset the ADC
IADC_reset(IADC0);

this->initialized_scan = false;
this->initialized_single = false;
this->current_adc_pin = PIN_NAME_NC;
}

void AdcClass::handle_dma_finished_callback()
{
if (!this->user_onsampling_finished_callback) {
return;
}

this->user_onsampling_finished_callback();
}

bool dma_transfer_finished_cb(unsigned int channel, unsigned int sequenceNo, void *userParam)
{
(void)channel;
(void)sequenceNo;
(void)userParam;

ADC.handle_dma_finished_callback();
return false;
}

const IADC_PosInput_t AdcClass::GPIO_to_ADC_pin_map[64] = {
// Port A
iadcPosInputPortAPin0,
Expand Down
Loading

0 comments on commit c51e6c0

Please sign in to comment.