Skip to content

Instantly share code, notes, and snippets.

@pabigot
Last active March 30, 2019 14:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pabigot/10775b4d62ee2edec36b51ec448e7f76 to your computer and use it in GitHub Desktop.
Save pabigot/10775b4d62ee2edec36b51ec448e7f76 to your computer and use it in GitHub Desktop.
Example code for Nordic devzone issue TBD
// SPDX-License-Identifier: CC-BY-SA-4.0
// Copyright 2019 Peter A. Bigot
/** See:
* https://gist.github.com/pabigot/10775b4d62ee2edec36b51ec448e7f76
* https://devzone.nordicsemi.com/f/nordic-q-a/45339/saadc-burst-problems-in-scan-vs-non-scan-acquisitions
* */
#include <cstdio>
#include <nrfcxx/clock.hpp>
#include <nrfcxx/periph.hpp>
#include <nrfcxx/sensor/adc.hpp>
/* Set to 0 to enable workaround */
#define CONFIG_BURST 1
#define CONFIG_OVERSAMPLE 2
namespace {
#define EVT_CALADC 0x01
#define EVT_ALARM 0x02
#define EVT_PROCESS 0x04
#define SEVT_CALIBRATEDONE 0x01
#define SEVT_STARTED 0x02
#define SEVT_END 0x04
#define SEVT_DONE 0x08
#define SEVT_RESULTDONE 0x10
#define SEVT_STOPPED 0x20
#define SEVT_RESTARTED 0x100
nrfcxx::event_set events;
auto& SAADC = *nrfcxx::nrf5::SAADC.instance();
int16_t volatile results[8];
void
start_saadc ()
{
SAADC.EVENTS_STARTED = 0;
SAADC.EVENTS_END = 0;
SAADC.EVENTS_DONE = 0;
SAADC.EVENTS_STOPPED = 0;
SAADC.EVENTS_CALIBRATEDONE = 0;
SAADC.INTENSET = SAADC_INTENSET_CH7LIMITL_Msk;
SAADC.ENABLE = 1;
SAADC.TASKS_START = 1;
}
void
stop_saadc ()
{
SAADC.ENABLE = 0;
}
void
setup_acquisition (bool multi)
{
unsigned int nresults;
unsigned int ain;
if (multi) {
nresults = 2;
ain = 4;
} else {
nresults = 1;
ain = 1;
}
#if 1
/* Workaround for PAN-212.
*
* This works when placed immediately before changing the CONFIG
* registers. It does not work if placed around ENABLE or after
* EVENTS_STARTED.
*
* From review of the documentation this appears to do a power-cycle
* of the SAADC peripheral. The following has been observed:
* * Settings to the INTEN register are preserved by this sequence
* * The CH, RESOLUTION, OVERSAMPLE, and RESULT registers are reset
* to their POR values by this sequence.
*/
*(volatile uint32_t *)0x40007FFC = 0;
*(volatile uint32_t *)0x40007FFC = 1;
#endif
SAADC.RESOLUTION = SAADC_RESOLUTION_VAL_14bit << SAADC_RESOLUTION_VAL_Pos;
SAADC.OVERSAMPLE = CONFIG_OVERSAMPLE;
for (auto ci = 0U; ci < 8; ++ci) {
results[ci] = 0;
if (ci < nresults) {
SAADC.CH[ci].CONFIG = 0x00051200; // REFSEL Vdd, 40 us
SAADC.CH[ci].PSELP = (SAADC_CH_PSELP_PSELP_AnalogInput0 + ain + ci) << SAADC_CH_PSELP_PSELP_Pos;
} else {
SAADC.CH[ci].CONFIG = 0x00020000;
SAADC.CH[ci].PSELP = SAADC_CH_PSELP_PSELP_NC << SAADC_CH_PSELP_PSELP_Pos;
}
#if (CONFIG_BURST - 0)
SAADC.CH[ci].CONFIG |= 0x01000000;
#endif
SAADC.CH[ci].PSELN = SAADC_CH_PSELN_PSELN_NC << SAADC_CH_PSELN_PSELN_Pos;
}
SAADC.RESULT.PTR = reinterpret_cast<uintptr_t>(results);
SAADC.RESULT.MAXCNT = nresults;
}
unsigned int
saadc_process ()
{
auto evts = 0U;
if (SAADC.EVENTS_STARTED) {
evts |= SEVT_STARTED;
SAADC.EVENTS_STARTED = 0;
SAADC.TASKS_SAMPLE = 1;
}
if (SAADC.EVENTS_END) {
evts |= SEVT_END;
SAADC.EVENTS_END = 0;
/* Explicit stop to ensure the ADC isn't consuming power after the
* sampling sequence has completed, and to ensure the START
* required for the next acquisition begins in a clean state. */
SAADC.EVENTS_STOPPED = 0;
SAADC.TASKS_STOP = 1;
}
if (SAADC.EVENTS_DONE) {
evts |= SEVT_DONE;
SAADC.EVENTS_DONE = 0;
#if !(CONFIG_BURST - 0)
/* Simulate BURST by triggering another sample if the collection
* is not complete. */
if (!(SEVT_END & evts)) {
evts |= SEVT_RESTARTED;
SAADC.TASKS_SAMPLE = 1;
}
#endif
}
if (SAADC.EVENTS_RESULTDONE) {
evts |= SEVT_RESULTDONE;
SAADC.EVENTS_RESULTDONE = 0;
}
if (SAADC.EVENTS_STOPPED) {
evts |= SEVT_STOPPED;
SAADC.EVENTS_STOPPED = 0;
}
return evts;
}
void
dump_adc ()
{
using namespace nrfcxx;
printf("ADC: ST %ld END %ld DONE %ld RDONE %ld CD %ld STOP %ld\n",
SAADC.EVENTS_STARTED, SAADC.EVENTS_END,
SAADC.EVENTS_DONE, SAADC.EVENTS_RESULTDONE,
SAADC.EVENTS_CALIBRATEDONE, SAADC.EVENTS_STOPPED);
printf("INTEN %lx STAT %lx ENA %lx\n",
SAADC.INTEN, SAADC.STATUS, SAADC.ENABLE);
printf("OVERSAMPLE %lu ; RESOLUTION %lu \n", SAADC.OVERSAMPLE, SAADC.RESOLUTION);
printf("RESULT %lu of %lu to %lx\n", SAADC.RESULT.AMOUNT, SAADC.RESULT.MAXCNT, SAADC.RESULT.PTR);
for (unsigned int ci = 0; ci < nrf5::SAADC.AUX; ++ci) {
auto& ch = SAADC.CH[ci];
printf("%u: %08lx %08lx %08lx\n", ci, ch.PSELP, ch.PSELN, ch.CONFIG);
}
}
} // anonymous namespace
int
main (void)
{
using namespace nrfcxx;
board::initialize();
using clock::uptime;
setvbuf(stdout, NULL, _IONBF, 0);
puts("\n\n" __FILE__ " " __DATE__ " " __TIME__);
auto alarm = clock::alarm::for_event<EVT_ALARM, true>(events);
alarm
.set_interval(1 * uptime::Frequency_Hz)
.set_deadline(alarm.interval())
.schedule();
events.set(EVT_ALARM);
unsigned int ctr = 0;
bool ready = true;
while (true) {
uptime::text_type buf;
event_set::cev();
auto pending = events.copy_and_clear();
int rc = saadc_process();
if (rc) {
if (SEVT_STOPPED & rc) {
stop_saadc();
printf("%s: %02x Completed %lu of %lu:", uptime::as_text(buf, uptime::now()), rc, SAADC.RESULT.AMOUNT, SAADC.RESULT.MAXCNT);
for (auto ci = 0U; ci < 8; ++ci) {
printf(" %d", results[ci]);
}
putchar('\n');
if (ctr <= 2) {
dump_adc();
}
ready = true;
} else {
printf("sevt %02x\n", rc);
}
}
if (!pending.empty()) {
if (pending.test_and_clear(EVT_ALARM)) {
if (!ready) {
printf("Sample failed to complete: %lu of %lu\n\t",
SAADC.RESULT.AMOUNT, SAADC.RESULT.MAXCNT);
for (auto ci = 0U; ci < 8; ++ci) {
printf(" %d", results[ci]);
}
putchar('\n');
dump_adc();
break;
}
printf("%s: Setting up %u\n", uptime::as_text(buf, uptime::now()), ctr);
setup_acquisition(1 & ctr);
start_saadc();
++ctr;
ready = false;
}
}
}
puts("Failed");
}
../examples/sensor/adc.cc Mar 26 2019 07:55:59
00:00:00.001: Setting up 0
sevt 02
00:00:00.004: 3c Completed 1 of 1: 1780 0 0 0 0 0 0 0
ADC: ST 0 END 0 DONE 0 RDONE 0 CD 0 STOP 0
INTEN 0 STAT 0 ENA 0
OVERSAMPLE 2
RESULT 1 of 1
0: 00000000 00000000 01051200
1: 00000000 00000000 01020000
2: 00000000 00000000 01020000
3: 00000000 00000000 01020000
4: 00000000 00000000 01020000
5: 00000000 00000000 01020000
6: 00000000 00000000 01020000
7: 00000000 00000000 01020000
00:00:01.000: Setting up 1
sevt 02
sevt 08
00:00:01.000: 3c Completed 2 of 2: 9 -3 0 0 0 0 0 0
ADC: ST 0 END 0 DONE 0 RDONE 0 CD 0 STOP 0
INTEN 0 STAT 0 ENA 0
OVERSAMPLE 2
RESULT 2 of 2
0: 00000000 00000000 01051200
1: 00000000 00000000 01051200
2: 00000000 00000000 01020000
3: 00000000 00000000 01020000
4: 00000000 00000000 01020000
5: 00000000 00000000 01020000
6: 00000000 00000000 01020000
7: 00000000 00000000 01020000
00:00:02.000: Setting up 2
sevt 02
sevt 08
00:00:02.000: 3c Completed 1 of 1: 1815 0 0 0 0 0 0 0
00:00:03.000: Setting up 3
sevt 02
sevt 08
sevt 18
Sample failed to complete: 1 of 2
-20 0 0 0 0 0 0 0
ADC: ST 0 END 0 DONE 0 RDONE 0 CD 0 STOP 0
INTEN 0 STAT 0 ENA 1
OVERSAMPLE 2
RESULT 1 of 2
0: 00000005 00000000 01051200
1: 00000006 00000000 01051200
2: 00000000 00000000 01020000
3: 00000000 00000000 01020000
4: 00000000 00000000 01020000
5: 00000000 00000000 01020000
6: 00000000 00000000 01020000
7: 00000000 00000000 01020000
Failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment