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); | ||||||
| 
 | 
 | ||||||
| #endif /* WATCH_H_ */ | /** @brief Disables the TRNG twice in order to work around silicon erratum 1.16.1.
 | ||||||
|  |  */ | ||||||
|  | void watch_disable_TRNG(); | ||||||
|  | 
 | ||||||
|  | #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