Skip to content

Commit c51e6c0

Browse files
silabs-bozontzofegyvesilabs-Gyapileonardocavagnis
authored
Release 2.3.0 (#161)
* 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]>
1 parent b049267 commit c51e6c0

File tree

309 files changed

+72529
-66
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

309 files changed

+72529
-66
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22
package/gen
33
package/gen_gsdk*
44
package/install_host*
5+
package/generate_gsdk.cfg
56
installed.json

boards.txt

Lines changed: 20 additions & 20 deletions
Large diffs are not rendered by default.

cores/silabs/Arduino.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,18 @@ void analogWrite(dac_channel_t dac_channel, int value);
105105
void analogWriteResolution(int resolution);
106106
void analogReadResolution(int resolution);
107107

108+
/***************************************************************************//**
109+
* Starts continuous ADC sample acquisition using DMA
110+
*
111+
* @param[in] pin The selected analog input pin
112+
* @param[in] buffer Pointer to the sampling buffer
113+
* @param[in] size The size of the sampling buffer
114+
* @param[in] user_onsampling_finished_callback Callback that gets called when an
115+
* acquisition finishes - pass 'nullptr' to stop sampling
116+
******************************************************************************/
117+
void analogReadDMA(PinName pin, uint32_t *buffer, uint32_t size, void (*user_onsampling_finished_callback)());
118+
void analogReadDMA(pin_size_t pin, uint32_t *buffer, uint32_t size, void (*user_onsampling_finished_callback)());
119+
108120
bool get_system_init_finished();
109121
uint32_t get_system_reset_cause();
110122
void escape_hatch();

cores/silabs/adc.cpp

Lines changed: 257 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,23 @@
2828

2929
using namespace arduino;
3030

31+
static bool dma_transfer_finished_cb(unsigned int channel, unsigned int sequenceNo, void *userParam);
32+
3133
AdcClass::AdcClass() :
32-
initialized(false),
34+
initialized_single(false),
35+
initialized_scan(false),
36+
paused_transfer(false),
3337
current_adc_pin(PD2),
3438
current_adc_reference(AR_VDD),
3539
current_read_resolution(this->max_read_resolution_bits),
40+
user_onsampling_finished_callback(nullptr),
3641
adc_mutex(nullptr)
3742
{
3843
this->adc_mutex = xSemaphoreCreateMutexStatic(&this->adc_mutex_buf);
3944
configASSERT(this->adc_mutex);
4045
}
4146

42-
void AdcClass::init(PinName pin, uint8_t reference)
47+
void AdcClass::init_single(PinName pin, uint8_t reference)
4348
{
4449
// Set up the ADC pin as an input
4550
pinMode(pin, INPUT);
@@ -126,16 +131,180 @@ void AdcClass::init(PinName pin, uint8_t reference)
126131
}
127132
}
128133

129-
this->initialized = true;
134+
this->initialized_scan = false;
135+
this->initialized_single = true;
136+
}
137+
138+
void AdcClass::init_scan(PinName pin, uint8_t reference)
139+
{
140+
// Set up the ADC pin as an input
141+
pinMode(pin, INPUT);
142+
143+
// Create ADC init structs with default values
144+
IADC_Init_t init = IADC_INIT_DEFAULT;
145+
IADC_AllConfigs_t all_configs = IADC_ALLCONFIGS_DEFAULT;
146+
IADC_InitScan_t init_scan = IADC_INITSCAN_DEFAULT;
147+
148+
// Scan table structure
149+
IADC_ScanTable_t scanTable = IADC_SCANTABLE_DEFAULT;
150+
151+
// Enable IADC0, GPIO and PRS clock branches
152+
CMU_ClockEnable(cmuClock_IADC0, true);
153+
CMU_ClockEnable(cmuClock_GPIO, true);
154+
CMU_ClockEnable(cmuClock_PRS, true);
155+
156+
// Shutdown between conversions to reduce current
157+
init.warmup = iadcWarmupNormal;
158+
159+
// Set the HFSCLK prescale value here
160+
init.srcClkPrescale = IADC_calcSrcClkPrescale(IADC0, 20000000, 0);
161+
162+
IADC_CfgReference_t sl_adc_reference;
163+
uint32_t sl_adc_vref;
164+
165+
// Set the voltage reference
166+
switch (reference) {
167+
case AR_INTERNAL1V2:
168+
sl_adc_reference = iadcCfgReferenceInt1V2;
169+
sl_adc_vref = 1200;
170+
break;
171+
172+
case AR_EXTERNAL_1V25:
173+
sl_adc_reference = iadcCfgReferenceExt1V25;
174+
sl_adc_vref = 1250;
175+
break;
176+
177+
case AR_VDD:
178+
sl_adc_reference = iadcCfgReferenceVddx;
179+
sl_adc_vref = 3300;
180+
break;
181+
182+
case AR_08VDD:
183+
sl_adc_reference = iadcCfgReferenceVddX0P8Buf;
184+
sl_adc_vref = 2640;
185+
break;
186+
187+
default:
188+
return;
189+
}
190+
191+
// Set the voltage reference
192+
all_configs.configs[0].reference = sl_adc_reference;
193+
all_configs.configs[0].vRef = sl_adc_vref;
194+
all_configs.configs[0].osrHighSpeed = iadcCfgOsrHighSpeed2x;
195+
all_configs.configs[0].analogGain = iadcCfgAnalogGain1x;
196+
197+
/*
198+
* CLK_SRC_ADC must be prescaled by some value greater than 1 to
199+
* derive the intended CLK_ADC frequency.
200+
* Based on the default 2x oversampling rate (OSRHS)...
201+
* conversion time = ((4 * OSRHS) + 2) / fCLK_ADC
202+
* ...which results in a maximum sampling rate of 833 ksps with the
203+
* 2-clock input multiplexer switching time is included.
204+
*/
205+
all_configs.configs[0].adcClkPrescale = IADC_calcAdcClkPrescale(IADC0,
206+
10000000,
207+
0,
208+
iadcCfgModeNormal,
209+
init.srcClkPrescale);
210+
211+
// Reset the ADC
212+
IADC_reset(IADC0);
213+
214+
// Only configure the ADC if it is not already running
215+
if (IADC0->CTRL == _IADC_CTRL_RESETVALUE) {
216+
IADC_init(IADC0, &init, &all_configs);
217+
}
218+
219+
// Assign the input pin
220+
uint32_t pin_index = pin - PIN_NAME_MIN;
221+
222+
// Trigger continuously once scan is started
223+
init_scan.triggerAction = iadcTriggerActionContinuous;
224+
// Set the SCANFIFODVL flag when scan FIFO holds 2 entries
225+
// The interrupt associated with the SCANFIFODVL flag in the IADC_IF register is not used
226+
init_scan.dataValidLevel = iadcFifoCfgDvl1;
227+
// Enable DMA wake-up to save the results when the specified FIFO level is hit
228+
init_scan.fifoDmaWakeup = true;
229+
230+
scanTable.entries[0].posInput = GPIO_to_ADC_pin_map[pin_index];
231+
scanTable.entries[0].includeInScan = true;
232+
233+
// Initialize scan
234+
IADC_initScan(IADC0, &init_scan, &scanTable);
235+
IADC_enableInt(IADC0, IADC_IEN_SCANTABLEDONE);
236+
237+
// Allocate the analog bus for ADC0 inputs
238+
// Port C and D are handled together
239+
// Even and odd pins on the same port have a different register value
240+
bool pin_is_even = (pin % 2 == 0);
241+
if (pin >= PD0 || pin >= PC0) {
242+
if (pin_is_even) {
243+
GPIO->CDBUSALLOC |= GPIO_CDBUSALLOC_CDEVEN0_ADC0;
244+
} else {
245+
GPIO->CDBUSALLOC |= GPIO_CDBUSALLOC_CDODD0_ADC0;
246+
}
247+
} else if (pin >= PB0) {
248+
if (pin_is_even) {
249+
GPIO->BBUSALLOC |= GPIO_BBUSALLOC_BEVEN0_ADC0;
250+
} else {
251+
GPIO->BBUSALLOC |= GPIO_BBUSALLOC_BODD0_ADC0;
252+
}
253+
} else {
254+
if (pin_is_even) {
255+
GPIO->ABUSALLOC |= GPIO_ABUSALLOC_AEVEN0_ADC0;
256+
} else {
257+
GPIO->ABUSALLOC |= GPIO_ABUSALLOC_AODD0_ADC0;
258+
}
259+
}
260+
261+
this->initialized_single = false;
262+
this->initialized_scan = true;
263+
}
264+
265+
sl_status_t AdcClass::init_dma(uint32_t *buffer, uint32_t size)
266+
{
267+
sl_status_t status;
268+
if (!this->initialized_scan) {
269+
return SL_STATUS_NOT_INITIALIZED;
270+
}
271+
272+
// Initialize DMA with default parameters
273+
DMADRV_Init();
274+
275+
// Allocate DMA channel
276+
status = DMADRV_AllocateChannel(&this->dma_channel, NULL);
277+
if (status != ECODE_EMDRV_DMADRV_OK) {
278+
return SL_STATUS_FAIL;
279+
}
280+
281+
// Trigger LDMA transfer on IADC scan completion
282+
LDMA_TransferCfg_t transferCfg = LDMA_TRANSFER_CFG_PERIPHERAL(ldmaPeripheralSignal_IADC0_IADC_SCAN);
283+
284+
/*
285+
* Set up a linked descriptor to save scan results to the
286+
* user-specified buffer. By linking the descriptor to itself
287+
* (the last argument is the relative jump in terms of the number of
288+
* descriptors), transfers will run continuously.
289+
*/
290+
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
291+
this->ldma_descriptor = (LDMA_Descriptor_t)LDMA_DESCRIPTOR_LINKREL_P2M_WORD(&(IADC0->SCANFIFODATA), buffer, size, 0);
292+
293+
DMADRV_LdmaStartTransfer((int)this->dma_channel, &transferCfg, &this->ldma_descriptor, dma_transfer_finished_cb, NULL);
294+
return SL_STATUS_OK;
130295
}
131296

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

136-
if (!this->initialized || pin != this->current_adc_pin) {
301+
if (this->initialized_scan) {
302+
this->scan_stop();
303+
}
304+
305+
if (!this->initialized_single || (pin != this->current_adc_pin)) {
137306
this->current_adc_pin = pin;
138-
this->init(this->current_adc_pin, this->current_adc_reference);
307+
this->init_single(this->current_adc_pin, this->current_adc_reference);
139308
}
140309
// Clear single done interrupt
141310
IADC_clearInt(IADC0, IADC_IF_SINGLEDONE);
@@ -162,18 +331,99 @@ void AdcClass::set_reference(uint8_t reference)
162331
}
163332
xSemaphoreTake(this->adc_mutex, portMAX_DELAY);
164333
this->current_adc_reference = reference;
165-
this->init(this->current_adc_pin, this->current_adc_reference);
334+
if (this->initialized_single) {
335+
this->init_single(this->current_adc_pin, this->current_adc_reference);
336+
} else if (this->initialized_scan) {
337+
this->init_scan(this->current_adc_pin, this->current_adc_reference);
338+
}
166339
xSemaphoreGive(this->adc_mutex);
167340
}
168341

169-
void AdcClass::set_read_resolution(uint8_t resolution) {
342+
void AdcClass::set_read_resolution(uint8_t resolution)
343+
{
170344
if (resolution > this->max_read_resolution_bits) {
171345
this->current_read_resolution = this->max_read_resolution_bits;
172346
return;
173347
}
174348
this->current_read_resolution = resolution;
175349
}
176350

351+
sl_status_t AdcClass::scan_start(PinName pin, uint32_t *buffer, uint32_t size, void (*user_onsampling_finished_callback)())
352+
{
353+
sl_status_t status = SL_STATUS_FAIL;
354+
xSemaphoreTake(this->adc_mutex, portMAX_DELAY);
355+
356+
if ((!this->initialized_scan && !this->initialized_single) || (pin != this->current_adc_pin)) {
357+
// Initialize in scan mode
358+
this->current_adc_pin = pin;
359+
this->user_onsampling_finished_callback = user_onsampling_finished_callback;
360+
this->init_scan(this->current_adc_pin, this->current_adc_reference);
361+
status = this->init_dma(buffer, size);
362+
} else if (this->initialized_scan && this->paused_transfer) {
363+
// Resume DMA transfer if paused
364+
status = DMADRV_ResumeTransfer(this->dma_channel);
365+
this->paused_transfer = false;
366+
} else if (this->initialized_single) {
367+
// Initialize in scan mode if it was initialized in single mode
368+
this->deinit();
369+
this->current_adc_pin = pin;
370+
this->user_onsampling_finished_callback = user_onsampling_finished_callback;
371+
this->init_scan(this->current_adc_pin, this->current_adc_reference);
372+
status = this->init_dma(buffer, size);
373+
} else {
374+
xSemaphoreGive(this->adc_mutex);
375+
return status;
376+
}
377+
378+
// Start the conversion and wait for results
379+
IADC_command(IADC0, iadcCmdStartScan);
380+
381+
xSemaphoreGive(this->adc_mutex);
382+
return status;
383+
}
384+
385+
void AdcClass::scan_stop()
386+
{
387+
// Pause sampling
388+
DMADRV_PauseTransfer(this->dma_channel);
389+
this->paused_transfer = true;
390+
}
391+
392+
void AdcClass::deinit()
393+
{
394+
// Stop sampling
395+
DMADRV_StopTransfer(this->dma_channel);
396+
397+
// Free resources
398+
DMADRV_FreeChannel(this->dma_channel);
399+
400+
// Reset the ADC
401+
IADC_reset(IADC0);
402+
403+
this->initialized_scan = false;
404+
this->initialized_single = false;
405+
this->current_adc_pin = PIN_NAME_NC;
406+
}
407+
408+
void AdcClass::handle_dma_finished_callback()
409+
{
410+
if (!this->user_onsampling_finished_callback) {
411+
return;
412+
}
413+
414+
this->user_onsampling_finished_callback();
415+
}
416+
417+
bool dma_transfer_finished_cb(unsigned int channel, unsigned int sequenceNo, void *userParam)
418+
{
419+
(void)channel;
420+
(void)sequenceNo;
421+
(void)userParam;
422+
423+
ADC.handle_dma_finished_callback();
424+
return false;
425+
}
426+
177427
const IADC_PosInput_t AdcClass::GPIO_to_ADC_pin_map[64] = {
178428
// Port A
179429
iadcPosInputPortAPin0,

0 commit comments

Comments
 (0)