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 <git@se30.xyz> Tested-by: Matheus Afonso Martins Moreira <matheus.a.m.moreira@gmail.com> Tested-on-hardware-by: Alex Maestas <git@se30.xyz> Tested-on-hardware-by: Matheus Afonso Martins Moreira <matheus.a.m.moreira@gmail.com> Reviewed-by: Wesley Aptekar-Cassels <me@wesleyac.com> Reviewed-by: Matheus Afonso Martins Moreira <matheus.a.m.moreira@gmail.com> Signed-off-by: Matheus Afonso Martins Moreira <matheus.a.m.moreira@gmail.com> GitHub-Pull-Request: https://github.com/joeycastillo/Sensor-Watch/pull/340 GitHub-Related-Issue: https://github.com/joeycastillo/Sensor-Watch/issues/361 GitHub-Related-Issue: https://github.com/joeycastillo/Sensor-Watch/issues/359 Reference: https://ww1.microchip.com/downloads/aemDocuments/documents/MCU32/ProductDocuments/Errata/SAM-L22-Family-Silicon-Errata-and-Data-Sheet-Clarification-DS80000782.pdf
This commit is contained in:
commit
592e18bf0e
@ -357,7 +357,7 @@ static uint32_t _get_true_entropy(void) {
|
|||||||
|
|
||||||
while (!hri_trng_get_INTFLAG_reg(TRNG, TRNG_INTFLAG_DATARDY)); // Wait for TRNG data to be ready
|
while (!hri_trng_get_INTFLAG_reg(TRNG, TRNG_INTFLAG_DATARDY)); // Wait for TRNG data to be ready
|
||||||
|
|
||||||
hri_trng_clear_CTRLA_ENABLE_bit(TRNG);
|
watch_disable_TRNG();
|
||||||
hri_mclk_clear_APBCMASK_TRNG_bit(MCLK);
|
hri_mclk_clear_APBCMASK_TRNG_bit(MCLK);
|
||||||
return hri_trng_read_DATA_reg(TRNG); // Read a single 32-bit word from TRNG and return it
|
return hri_trng_read_DATA_reg(TRNG); // Read a single 32-bit word from TRNG and return it
|
||||||
#endif
|
#endif
|
||||||
|
@ -255,7 +255,8 @@ uint32_t get_true_entropy(void) {
|
|||||||
|
|
||||||
while (!hri_trng_get_INTFLAG_reg(TRNG, TRNG_INTFLAG_DATARDY)); // Wait for TRNG data to be ready
|
while (!hri_trng_get_INTFLAG_reg(TRNG, TRNG_INTFLAG_DATARDY)); // Wait for TRNG data to be ready
|
||||||
|
|
||||||
hri_trng_clear_CTRLA_ENABLE_bit(TRNG);
|
watch_disable_TRNG();
|
||||||
|
|
||||||
hri_mclk_clear_APBCMASK_TRNG_bit(MCLK);
|
hri_mclk_clear_APBCMASK_TRNG_bit(MCLK);
|
||||||
return hri_trng_read_DATA_reg(TRNG); // Read a single 32-bit word from TRNG and return it
|
return hri_trng_read_DATA_reg(TRNG); // Read a single 32-bit word from TRNG and return it
|
||||||
#endif
|
#endif
|
||||||
|
@ -70,6 +70,16 @@ extern "C" {
|
|||||||
*/
|
*/
|
||||||
int32_t _set_sleep_mode(const uint8_t mode);
|
int32_t _set_sleep_mode(const uint8_t mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the sleep mode for the device
|
||||||
|
*
|
||||||
|
* This function gets the sleep mode for the device.
|
||||||
|
*
|
||||||
|
* \return the current value of the sleep mode configuration bits
|
||||||
|
*/
|
||||||
|
int32_t _get_sleep_mode(void);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Reset MCU
|
* \brief Reset MCU
|
||||||
*/
|
*/
|
||||||
|
@ -57,6 +57,15 @@ int sleep(const uint8_t mode)
|
|||||||
if (ERR_NONE != _set_sleep_mode(mode))
|
if (ERR_NONE != _set_sleep_mode(mode))
|
||||||
return ERR_INVALID_ARG;
|
return ERR_INVALID_ARG;
|
||||||
|
|
||||||
|
// wait for the mode set to actually take, per note in Microchip data
|
||||||
|
// sheet DS60001465, section 19.8.2:
|
||||||
|
//
|
||||||
|
// A small latency happens between the store instruction and actual
|
||||||
|
// writing of the SLEEPCFG register due to bridges. Software has to make
|
||||||
|
// sure the SLEEPCFG register reads the wanted value before issuing WFI
|
||||||
|
// instruction.
|
||||||
|
while(_get_sleep_mode() != mode);
|
||||||
|
|
||||||
_go_to_sleep();
|
_go_to_sleep();
|
||||||
|
|
||||||
return ERR_NONE;
|
return ERR_NONE;
|
||||||
|
@ -63,6 +63,14 @@ int32_t _set_sleep_mode(const uint8_t mode)
|
|||||||
return ERR_NONE;
|
return ERR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the sleep mode for the device
|
||||||
|
*/
|
||||||
|
int32_t _get_sleep_mode()
|
||||||
|
{
|
||||||
|
return hri_pm_read_SLEEPCFG_SLEEPMODE_bf(PM);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Set performance level
|
* \brief Set performance level
|
||||||
*/
|
*/
|
||||||
|
@ -220,6 +220,5 @@ void Reset_Handler(void)
|
|||||||
*/
|
*/
|
||||||
void Dummy_Handler(void)
|
void Dummy_Handler(void)
|
||||||
{
|
{
|
||||||
while (1) {
|
NVIC_SystemReset();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "hpl_systick_config.h"
|
||||||
|
|
||||||
#include "watch_extint.h"
|
#include "watch_extint.h"
|
||||||
|
|
||||||
// this warning only appears when you `make BOARD=OSO-SWAT-A1-02`. it's annoying,
|
// 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) {
|
|||||||
// disable brownout detector interrupt, which could inadvertently wake us up.
|
// disable brownout detector interrupt, which could inadvertently wake us up.
|
||||||
SUPC->INTENCLR.bit.BOD33DET = 1;
|
SUPC->INTENCLR.bit.BOD33DET = 1;
|
||||||
|
|
||||||
|
// per Microchip datasheet clarification DS80000782,
|
||||||
|
// work around silicon erratum 1.8.4 by disabling the SysTick interrupt, which is
|
||||||
|
// enabled as part of driver init, before going to sleep.
|
||||||
|
SysTick->CTRL = SysTick->CTRL & ~(CONF_SYSTICK_TICKINT << SysTick_CTRL_TICKINT_Pos);
|
||||||
|
|
||||||
// disable all pins
|
// disable all pins
|
||||||
_watch_disable_all_pins_except_rtc();
|
_watch_disable_all_pins_except_rtc();
|
||||||
|
|
||||||
// enter standby (4); we basically hang out here until an interrupt wakes us.
|
// enter standby (4); we basically hang out here until an interrupt wakes us.
|
||||||
sleep(4);
|
sleep(4);
|
||||||
|
|
||||||
// and we awake! re-enable the brownout detector
|
// and we awake! re-enable the brownout detector and SysTick interrupt
|
||||||
SUPC->INTENSET.bit.BOD33DET = 1;
|
SUPC->INTENSET.bit.BOD33DET = 1;
|
||||||
|
SysTick->CTRL = SysTick->CTRL | (CONF_SYSTICK_TICKINT << SysTick_CTRL_TICKINT_Pos);
|
||||||
|
|
||||||
// call app_setup so the app can re-enable everything we disabled.
|
// call app_setup so the app can re-enable everything we disabled.
|
||||||
app_setup();
|
app_setup();
|
||||||
|
@ -35,6 +35,12 @@ void _watch_init(void) {
|
|||||||
|
|
||||||
// Use switching regulator for lower power consumption.
|
// Use switching regulator for lower power consumption.
|
||||||
SUPC->VREG.bit.SEL = 1;
|
SUPC->VREG.bit.SEL = 1;
|
||||||
|
|
||||||
|
// per Microchip datasheet clarification DS80000782,
|
||||||
|
// work around silicon erratum 1.7.2, which causes the microcontroller to lock up on leaving standby:
|
||||||
|
// request that the voltage regulator run in standby, and also that it switch to PL0.
|
||||||
|
SUPC->VREG.bit.RUNSTDBY = 1;
|
||||||
|
SUPC->VREG.bit.STDBYPL0 = 1;
|
||||||
while(!SUPC->STATUS.bit.VREGRDY); // wait for voltage regulator to become ready
|
while(!SUPC->STATUS.bit.VREGRDY); // wait for voltage regulator to become ready
|
||||||
|
|
||||||
// check the battery voltage...
|
// check the battery voltage...
|
||||||
@ -106,12 +112,21 @@ int getentropy(void *buf, size_t buflen) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hri_trng_clear_CTRLA_ENABLE_bit(TRNG);
|
watch_disable_TRNG();
|
||||||
hri_mclk_clear_APBCMASK_TRNG_bit(MCLK);
|
hri_mclk_clear_APBCMASK_TRNG_bit(MCLK);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void watch_disable_TRNG() {
|
||||||
|
// per Microchip datasheet clarification DS80000782,
|
||||||
|
// silicon erratum 1.16.1 indicates that the TRNG may leave internal components powered after being disabled.
|
||||||
|
// the workaround is to disable the TRNG by clearing the control register, twice.
|
||||||
|
hri_trng_write_CTRLA_reg(TRNG, 0);
|
||||||
|
hri_trng_write_CTRLA_reg(TRNG, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void _watch_enable_tcc(void) {
|
void _watch_enable_tcc(void) {
|
||||||
// clock TCC0 with the main clock (8 MHz) and enable the peripheral clock.
|
// clock TCC0 with the main clock (8 MHz) and enable the peripheral clock.
|
||||||
hri_gclk_write_PCHCTRL_reg(GCLK, TCC0_GCLK_ID, GCLK_PCHCTRL_GEN_GCLK0_Val | GCLK_PCHCTRL_CHEN);
|
hri_gclk_write_PCHCTRL_reg(GCLK, TCC0_GCLK_ID, GCLK_PCHCTRL_GEN_GCLK0_Val | GCLK_PCHCTRL_CHEN);
|
||||||
|
@ -96,4 +96,8 @@ void watch_reset_to_bootloader(void);
|
|||||||
*/
|
*/
|
||||||
int read(int file, char *ptr, int len);
|
int read(int file, char *ptr, int len);
|
||||||
|
|
||||||
|
/** @brief Disables the TRNG twice in order to work around silicon erratum 1.16.1.
|
||||||
|
*/
|
||||||
|
void watch_disable_TRNG();
|
||||||
|
|
||||||
#endif /* WATCH_H_ */
|
#endif /* WATCH_H_ */
|
@ -57,6 +57,8 @@ void _watch_disable_tcc(void) {}
|
|||||||
|
|
||||||
void _watch_enable_usb(void) {}
|
void _watch_enable_usb(void) {}
|
||||||
|
|
||||||
|
void watch_disable_TRNG() {}
|
||||||
|
|
||||||
// this function ends up getting called by printf to log stuff to the USB console.
|
// this function ends up getting called by printf to log stuff to the USB console.
|
||||||
int _write(int file, char *ptr, int len) {
|
int _write(int file, char *ptr, int len) {
|
||||||
// TODO: (a2) hook to UI
|
// TODO: (a2) hook to UI
|
||||||
|
Loading…
x
Reference in New Issue
Block a user