Skip to content

Commit d35658f

Browse files
authored
microbit-v2: Add HW timer for delays instead of busy "for" loops
2 parents 798b9e7 + 1acecc8 commit d35658f

File tree

2 files changed

+59
-8
lines changed

2 files changed

+59
-8
lines changed

source/board/microbitv2/kl27z/pwr_mon.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "fsl_pmc.h"
2626
#include "fsl_port.h"
2727
#include "fsl_gpio.h"
28+
#include "fsl_tpm.h"
2829

2930
#define ADC_VBG_CHANNEL 27U
3031
#define ADC_VBG_MUX (kADC16_ChannelMuxA)
@@ -38,6 +39,11 @@ static void pwr_mon_bandgap_init(void);
3839
static uint32_t pwr_mon_read_vbg(uint32_t channelGroup);
3940
static uint32_t pwr_mon_adc_to_mv(uint32_t raw_adc);
4041

42+
void TPM0_IRQHandler(void);
43+
44+
extern volatile bool tpmIsrFlag;
45+
extern uint32_t tpm_source_clock;
46+
4147
void pwr_mon_init(void)
4248
{
4349
gpio_pin_config_t pin_config = {
@@ -85,11 +91,15 @@ power_source_t pwr_mon_get_power_source(void) {
8591
}
8692

8793
uint32_t pwr_mon_get_vbat_mv(void) {
94+
/* Set timer period 3ms*/
95+
TPM_SetTimerPeriod(TPM0, USEC_TO_COUNT(3000U, tpm_source_clock));
8896
// Enable voltage divider to take measurement
8997
GPIO_PinWrite(PIN_RUN_VBAT_SENSE_GPIO, PIN_RUN_VBAT_SENSE_BIT, 1);
9098
// Add a ~3ms delay to allow the 100nF capacitors to charge to about 3*RC.
91-
// 3 clock cycles per loop at -O2 ARMCC optimization
92-
for (uint32_t count = 48000; count > 0UL; count--);
99+
TPM_StartTimer(TPM0, kTPM_SystemClock);
100+
while (false == tpmIsrFlag);
101+
tpmIsrFlag = false;
102+
93103
uint32_t bat_adc = adc_read_channel(0, PIN_VMON_BAT_ADC_CH, PIN_VMON_BAT_ADC_MUX);
94104
// Disable voltage divider
95105
GPIO_PinWrite(PIN_RUN_VBAT_SENSE_GPIO, PIN_RUN_VBAT_SENSE_BIT, 0);

source/board/microbitv2/microbitv2.c

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,19 @@
4747
#include "adc.h"
4848
#include "fsl_port.h"
4949
#include "fsl_gpio.h"
50+
#include "fsl_tpm.h"
5051

52+
volatile bool tpmIsrFlag = false;
53+
uint32_t tpm_source_clock;
54+
55+
void TPM0_IRQHandler(void)
56+
{
57+
/* Clear interrupt flag.*/
58+
TPM_ClearStatusFlags(TPM0, kTPM_TimeOverflowFlag);
59+
tpmIsrFlag = true;
60+
TPM_StopTimer(TPM0);
61+
__DSB();
62+
}
5163
#endif
5264

5365
#ifdef DRAG_N_DROP_SUPPORT
@@ -109,6 +121,25 @@ static mb_version_t read_brd_rev_id(void) {
109121
mb_version_t board_version = BOARD_VERSION_2_DEF;
110122
uint32_t board_rev_id_adc = 0;
111123
uint32_t board_rev_id_mv = 0;
124+
125+
tpm_config_t tpmInfo;
126+
127+
/* Select the clock source for the TPM counter as kCLOCK_McgIrc48MClk */
128+
CLOCK_SetTpmClock(1U);
129+
130+
TPM_GetDefaultConfig(&tpmInfo);
131+
132+
/* TPM clock divide by TPM_PRESCALER */
133+
tpmInfo.prescale = kTPM_Prescale_Divide_4;
134+
135+
/* Initialize TPM module */
136+
TPM_Init(TPM0, &tpmInfo);
137+
138+
TPM_EnableInterrupts(TPM0, kTPM_TimeOverflowInterruptEnable);
139+
140+
EnableIRQ(TPM0_IRQn);
141+
142+
tpm_source_clock = (CLOCK_GetFreq(kCLOCK_McgIrc48MClk) / 4);
112143

113144
// Set Board Rev ID pin as output but pin disabled
114145
PORT_SetPinMux(PIN_BOARD_REV_ID_PORT , PIN_BOARD_REV_ID_BIT, kPORT_PinDisabledOrAnalog);
@@ -118,19 +149,26 @@ static mb_version_t read_brd_rev_id(void) {
118149
adc_init();
119150

120151
// 1. Discharge capacitor
152+
/* Set timer period 3ms*/
153+
TPM_SetTimerPeriod(TPM0, USEC_TO_COUNT(3000U, tpm_source_clock));
121154
// Drive BRD_REV_ID pin to low
122155
GPIO_PortClear(PIN_BOARD_REV_ID_GPIO, PIN_BOARD_REV_ID);
123156
PORT_SetPinMux(PIN_BOARD_REV_ID_PORT , PIN_BOARD_REV_ID_BIT, kPORT_MuxAsGpio);
124157
// Add a 3ms delay to allow the 100nF Cap to discharge
125158
// at least 5*RC with 4700R.
126-
for (uint32_t count = 16 * 3000; count > 0UL; count--);
159+
TPM_StartTimer(TPM0, kTPM_SystemClock);
160+
while (false == tpmIsrFlag);
161+
tpmIsrFlag = false;
127162

128163
// 2. Charge capacitor for 100us
164+
/* Set timer period slightly below 100us to account for overheads */
165+
TPM_SetTimerPeriod(TPM0, USEC_TO_COUNT(98U, tpm_source_clock));
129166
// Drive BRD_REV_ID pin to high
130167
GPIO_PortSet(PIN_BOARD_REV_ID_GPIO, PIN_BOARD_REV_ID);
131168
// Add a ~100us delay
132-
// 3 clock cycles per loop at -O2 ARMCC optimization
133-
for (uint32_t count = 1600; count > 0UL; count--);
169+
TPM_StartTimer(TPM0, kTPM_SystemClock);
170+
while (false == tpmIsrFlag);
171+
tpmIsrFlag = false;
134172
// Change pin to ADC (High-Z). Capacitor will stop charging
135173
PORT_SetPinMux(PIN_BOARD_REV_ID_PORT , PIN_BOARD_REV_ID_BIT, kPORT_PinDisabledOrAnalog);
136174

@@ -139,12 +177,16 @@ static mb_version_t read_brd_rev_id(void) {
139177
board_rev_id_mv = board_rev_id_adc * 3300 / 0xFFF; // Convert ADC 12-bit value to mV with 3.3V reference
140178

141179
// 4. Discharge capacitor
180+
/* Set timer period 3ms*/
181+
TPM_SetTimerPeriod(TPM0, USEC_TO_COUNT(3000U, tpm_source_clock));
142182
// Drive BRD_REV_ID pin to low
143183
GPIO_PortClear(PIN_BOARD_REV_ID_GPIO, PIN_BOARD_REV_ID);
144184
PORT_SetPinMux(PIN_BOARD_REV_ID_PORT , PIN_BOARD_REV_ID_BIT, kPORT_MuxAsGpio);
145185
// Add a 3ms delay to allow the 100nF Cap to discharge
146186
// at least 5*RC with 4700R.
147-
for (uint32_t count = 16 * 3000; count > 0UL; count--);
187+
TPM_StartTimer(TPM0, kTPM_SystemClock);
188+
while (false == tpmIsrFlag);
189+
tpmIsrFlag = false;
148190

149191
// 5. Identify board ID depending on voltage
150192
if ( board_rev_id_mv > BRD_ID_1_LOWER_THR_V && board_rev_id_mv < BRD_ID_1_UPPER_THR_V) {
@@ -153,8 +195,7 @@ static mb_version_t read_brd_rev_id(void) {
153195
board_version = BOARD_VERSION_2_DEF;
154196
}
155197

156-
return BOARD_VERSION_2_0;
157-
//return board_version;
198+
return board_version;
158199
}
159200

160201
#elif defined(INTERFACE_NRF52820)

0 commit comments

Comments
 (0)