Skip to content

Commit 592e18b

Browse files
Merge branch 'silicon-errata' into advanced
Implements the recommended workarounds for numerous silicon errata, reducing power consumption and preventing freezes and hard faults. Tested-by: Alex Maestas <[email protected]> Tested-by: Matheus Afonso Martins Moreira <[email protected]> Tested-on-hardware-by: Alex Maestas <[email protected]> Tested-on-hardware-by: Matheus Afonso Martins Moreira <[email protected]> Reviewed-by: Wesley Aptekar-Cassels <[email protected]> Reviewed-by: Matheus Afonso Martins Moreira <[email protected]> Signed-off-by: Matheus Afonso Martins Moreira <[email protected]> GitHub-Pull-Request: joeycastillo#340 GitHub-Related-Issue: joeycastillo#361 GitHub-Related-Issue: joeycastillo#359 Reference: https://ww1.microchip.com/downloads/aemDocuments/documents/MCU32/ProductDocuments/Errata/SAM-L22-Family-Silicon-Errata-and-Data-Sheet-Clarification-DS80000782.pdf
2 parents a4ee7dd + a2a60eb commit 592e18b

File tree

10 files changed

+63
-7
lines changed

10 files changed

+63
-7
lines changed

Diff for: movement/watch_faces/complication/randonaut_face.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ static uint32_t _get_true_entropy(void) {
357357

358358
while (!hri_trng_get_INTFLAG_reg(TRNG, TRNG_INTFLAG_DATARDY)); // Wait for TRNG data to be ready
359359

360-
hri_trng_clear_CTRLA_ENABLE_bit(TRNG);
360+
watch_disable_TRNG();
361361
hri_mclk_clear_APBCMASK_TRNG_bit(MCLK);
362362
return hri_trng_read_DATA_reg(TRNG); // Read a single 32-bit word from TRNG and return it
363363
#endif

Diff for: movement/watch_faces/complication/toss_up_face.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,8 @@ uint32_t get_true_entropy(void) {
255255

256256
while (!hri_trng_get_INTFLAG_reg(TRNG, TRNG_INTFLAG_DATARDY)); // Wait for TRNG data to be ready
257257

258-
hri_trng_clear_CTRLA_ENABLE_bit(TRNG);
258+
watch_disable_TRNG();
259+
259260
hri_mclk_clear_APBCMASK_TRNG_bit(MCLK);
260261
return hri_trng_read_DATA_reg(TRNG); // Read a single 32-bit word from TRNG and return it
261262
#endif

Diff for: watch-library/hardware/hal/include/hpl_sleep.h

+10
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,16 @@ extern "C" {
7070
*/
7171
int32_t _set_sleep_mode(const uint8_t mode);
7272

73+
/**
74+
* \brief Get the sleep mode for the device
75+
*
76+
* This function gets the sleep mode for the device.
77+
*
78+
* \return the current value of the sleep mode configuration bits
79+
*/
80+
int32_t _get_sleep_mode(void);
81+
82+
7383
/**
7484
* \brief Reset MCU
7585
*/

Diff for: watch-library/hardware/hal/src/hal_sleep.c

+9
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,15 @@ int sleep(const uint8_t mode)
5757
if (ERR_NONE != _set_sleep_mode(mode))
5858
return ERR_INVALID_ARG;
5959

60+
// wait for the mode set to actually take, per note in Microchip data
61+
// sheet DS60001465, section 19.8.2:
62+
//
63+
// A small latency happens between the store instruction and actual
64+
// writing of the SLEEPCFG register due to bridges. Software has to make
65+
// sure the SLEEPCFG register reads the wanted value before issuing WFI
66+
// instruction.
67+
while(_get_sleep_mode() != mode);
68+
6069
_go_to_sleep();
6170

6271
return ERR_NONE;

Diff for: watch-library/hardware/hpl/pm/hpl_pm.c

+8
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,14 @@ int32_t _set_sleep_mode(const uint8_t mode)
6363
return ERR_NONE;
6464
}
6565

66+
/**
67+
* \brief Get the sleep mode for the device
68+
*/
69+
int32_t _get_sleep_mode()
70+
{
71+
return hri_pm_read_SLEEPCFG_SLEEPMODE_bf(PM);
72+
}
73+
6674
/**
6775
* \brief Set performance level
6876
*/

Diff for: watch-library/hardware/startup_saml22.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,5 @@ void Reset_Handler(void)
220220
*/
221221
void Dummy_Handler(void)
222222
{
223-
while (1) {
224-
}
223+
NVIC_SystemReset();
225224
}

Diff for: watch-library/hardware/watch/watch_deepsleep.c

+9-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
* SOFTWARE.
2323
*/
2424

25+
#include "hpl_systick_config.h"
26+
2527
#include "watch_extint.h"
2628

2729
// this warning only appears when you `make BOARD=OSO-SWAT-A1-02`. it's annoying,
@@ -158,14 +160,20 @@ void watch_enter_sleep_mode(void) {
158160
// disable brownout detector interrupt, which could inadvertently wake us up.
159161
SUPC->INTENCLR.bit.BOD33DET = 1;
160162

163+
// per Microchip datasheet clarification DS80000782,
164+
// work around silicon erratum 1.8.4 by disabling the SysTick interrupt, which is
165+
// enabled as part of driver init, before going to sleep.
166+
SysTick->CTRL = SysTick->CTRL & ~(CONF_SYSTICK_TICKINT << SysTick_CTRL_TICKINT_Pos);
167+
161168
// disable all pins
162169
_watch_disable_all_pins_except_rtc();
163170

164171
// enter standby (4); we basically hang out here until an interrupt wakes us.
165172
sleep(4);
166173

167-
// and we awake! re-enable the brownout detector
174+
// and we awake! re-enable the brownout detector and SysTick interrupt
168175
SUPC->INTENSET.bit.BOD33DET = 1;
176+
SysTick->CTRL = SysTick->CTRL | (CONF_SYSTICK_TICKINT << SysTick_CTRL_TICKINT_Pos);
169177

170178
// call app_setup so the app can re-enable everything we disabled.
171179
app_setup();

Diff for: watch-library/hardware/watch/watch_private.c

+16-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ void _watch_init(void) {
3535

3636
// Use switching regulator for lower power consumption.
3737
SUPC->VREG.bit.SEL = 1;
38+
39+
// per Microchip datasheet clarification DS80000782,
40+
// work around silicon erratum 1.7.2, which causes the microcontroller to lock up on leaving standby:
41+
// request that the voltage regulator run in standby, and also that it switch to PL0.
42+
SUPC->VREG.bit.RUNSTDBY = 1;
43+
SUPC->VREG.bit.STDBYPL0 = 1;
3844
while(!SUPC->STATUS.bit.VREGRDY); // wait for voltage regulator to become ready
3945

4046
// check the battery voltage...
@@ -106,12 +112,21 @@ int getentropy(void *buf, size_t buflen) {
106112
}
107113
}
108114

109-
hri_trng_clear_CTRLA_ENABLE_bit(TRNG);
115+
watch_disable_TRNG();
110116
hri_mclk_clear_APBCMASK_TRNG_bit(MCLK);
111117

112118
return 0;
113119
}
114120

121+
void watch_disable_TRNG() {
122+
// per Microchip datasheet clarification DS80000782,
123+
// silicon erratum 1.16.1 indicates that the TRNG may leave internal components powered after being disabled.
124+
// the workaround is to disable the TRNG by clearing the control register, twice.
125+
hri_trng_write_CTRLA_reg(TRNG, 0);
126+
hri_trng_write_CTRLA_reg(TRNG, 0);
127+
}
128+
129+
115130
void _watch_enable_tcc(void) {
116131
// clock TCC0 with the main clock (8 MHz) and enable the peripheral clock.
117132
hri_gclk_write_PCHCTRL_reg(GCLK, TCC0_GCLK_ID, GCLK_PCHCTRL_GEN_GCLK0_Val | GCLK_PCHCTRL_CHEN);

Diff for: watch-library/shared/watch/watch.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -96,4 +96,8 @@ void watch_reset_to_bootloader(void);
9696
*/
9797
int read(int file, char *ptr, int len);
9898

99-
#endif /* WATCH_H_ */
99+
/** @brief Disables the TRNG twice in order to work around silicon erratum 1.16.1.
100+
*/
101+
void watch_disable_TRNG();
102+
103+
#endif /* WATCH_H_ */

Diff for: watch-library/simulator/watch/watch_private.c

+2
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ void _watch_disable_tcc(void) {}
5757

5858
void _watch_enable_usb(void) {}
5959

60+
void watch_disable_TRNG() {}
61+
6062
// this function ends up getting called by printf to log stuff to the USB console.
6163
int _write(int file, char *ptr, int len) {
6264
// TODO: (a2) hook to UI

0 commit comments

Comments
 (0)