Skip to content

Commit 6e984a8

Browse files
patrickmtdrashna
authored andcommitted
Update to arm_atsam wait and timer routines
Microsecond (us) delays are now handled by a busy wait loop according to MCU frequency. This replaces the system counter method which had an overhead of around 12us. TC5 device and supporting routines removed as it was the old us delay counter. wait_ms is now properly a macro to CLK_delay_ms. wait_us is now properly a macro to CLK_delay_us. Removed CLK_get_us as it has no use. All calls to CLK_get_ms() have been replaced by timer_read64() with corrected typing. All calls to CLK_delay_ms() have been replaced by wait_ms(). All calls to CLK_delay_us() have been replaced by wait_us() and timings verified or updated as needed after review on scope. Corrected typing of variables using 64bit ms timer readings if needed.
1 parent 2898699 commit 6e984a8

File tree

12 files changed

+61
-133
lines changed

12 files changed

+61
-133
lines changed

keyboards/massdrop/alt/matrix.c

+3-9
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,6 @@ void matrix_init(void)
7979
matrix_init_quantum();
8080
}
8181

82-
#define MATRIX_SCAN_DELAY 10 //Delay after setting a col to output (in us)
83-
8482
uint64_t mdebouncing = 0;
8583
uint8_t matrix_scan(void)
8684
{
@@ -89,17 +87,15 @@ uint8_t matrix_scan(void)
8987
uint8_t col;
9088
uint32_t scans[2]; //PA PB
9189

92-
if (CLK_get_ms() < mdebouncing) return 1; //mdebouncing == 0 when no debouncing active
93-
94-
//DBG_1_OFF; //Profiling scans
90+
if (timer_read64() < mdebouncing) return 1; //mdebouncing == 0 when no debouncing active
9591

9692
memset(mlatest, 0, MATRIX_ROWS * sizeof(matrix_row_t)); //Zero the result buffer
9793

9894
for (col = 0; col < MATRIX_COLS; col++)
9995
{
10096
PORT->Group[col_ports[col]].OUTSET.reg = 1 << col_pins[col]; //Set col output
10197

102-
CLK_delay_us(MATRIX_SCAN_DELAY); //Delay for output
98+
wait_us(1); //Delay for output
10399

104100
scans[PA] = PORT->Group[PA].IN.reg & row_masks[PA]; //Read PA row pins data
105101
scans[PB] = PORT->Group[PB].IN.reg & row_masks[PB]; //Read PB row pins data
@@ -132,11 +128,9 @@ uint8_t matrix_scan(void)
132128
else
133129
{
134130
//Begin or extend debounce on change
135-
mdebouncing = CLK_get_ms() + DEBOUNCING_DELAY;
131+
mdebouncing = timer_read64() + DEBOUNCING_DELAY;
136132
}
137133

138-
//DBG_1_ON; //Profiling scans
139-
140134
matrix_scan_quantum();
141135

142136
return 1;

keyboards/massdrop/ctrl/matrix.c

+3-9
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,6 @@ void matrix_init(void)
7979
matrix_init_quantum();
8080
}
8181

82-
#define MATRIX_SCAN_DELAY 10 //Delay after setting a col to output (in us)
83-
8482
uint64_t mdebouncing = 0;
8583
uint8_t matrix_scan(void)
8684
{
@@ -89,17 +87,15 @@ uint8_t matrix_scan(void)
8987
uint8_t col;
9088
uint32_t scans[2]; //PA PB
9189

92-
if (CLK_get_ms() < mdebouncing) return 1; //mdebouncing == 0 when no debouncing active
93-
94-
//DBG_1_OFF; //Profiling scans
90+
if (timer_read64() < mdebouncing) return 1; //mdebouncing == 0 when no debouncing active
9591

9692
memset(mlatest, 0, MATRIX_ROWS * sizeof(matrix_row_t)); //Zero the result buffer
9793

9894
for (col = 0; col < MATRIX_COLS; col++)
9995
{
10096
PORT->Group[col_ports[col]].OUTSET.reg = 1 << col_pins[col]; //Set col output
10197

102-
CLK_delay_us(MATRIX_SCAN_DELAY); //Delay for output
98+
wait_us(1); //Delay for output
10399

104100
scans[PA] = PORT->Group[PA].IN.reg & row_masks[PA]; //Read PA row pins data
105101
scans[PB] = PORT->Group[PB].IN.reg & row_masks[PB]; //Read PB row pins data
@@ -132,11 +128,9 @@ uint8_t matrix_scan(void)
132128
else
133129
{
134130
//Begin or extend debounce on change
135-
mdebouncing = CLK_get_ms() + DEBOUNCING_DELAY;
131+
mdebouncing = timer_read64() + DEBOUNCING_DELAY;
136132
}
137133

138-
//DBG_1_ON; //Profiling scans
139-
140134
matrix_scan_quantum();
141135

142136
return 1;

tmk_core/common/arm_atsam/timer.c

+2-18
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ void set_time(uint64_t tset)
99

1010
void timer_init(void)
1111
{
12-
ms_clk = 0;
12+
timer_clear();
1313
}
1414

1515
uint16_t timer_read(void)
@@ -37,23 +37,7 @@ uint32_t timer_elapsed32(uint32_t tlast)
3737
return TIMER_DIFF_32(timer_read32(), tlast);
3838
}
3939

40-
uint32_t timer_elapsed64(uint32_t tlast)
41-
{
42-
uint64_t tnow = timer_read64();
43-
return (tnow >= tlast ? tnow - tlast : UINT64_MAX - tlast + tnow);
44-
}
45-
4640
void timer_clear(void)
4741
{
48-
ms_clk = 0;
49-
}
50-
51-
void wait_ms(uint64_t msec)
52-
{
53-
CLK_delay_ms(msec);
54-
}
55-
56-
void wait_us(uint16_t usec)
57-
{
58-
CLK_delay_us(usec);
42+
set_time(0);
5943
}

tmk_core/common/wait.h

+4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ extern "C" {
1515
# include "ch.h"
1616
# define wait_ms(ms) chThdSleepMilliseconds(ms)
1717
# define wait_us(us) chThdSleepMicroseconds(us)
18+
#elif defined PROTOCOL_ARM_ATSAM
19+
# include "clks.h"
20+
# define wait_ms(ms) CLK_delay_ms(ms)
21+
# define wait_us(us) CLK_delay_us(us)
1822
#elif defined(__arm__)
1923
# include "wait_api.h"
2024
#else // Unit tests

tmk_core/protocol/arm_atsam/arm_atsam_protocol.h

+2
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
2121
#include "samd51j18a.h"
2222
#include "md_bootloader.h"
2323

24+
#include "timer.h"
2425
#include "d51_util.h"
2526
#include "clks.h"
27+
#include "wait.h"
2628
#include "adc.h"
2729
#include "i2c_master.h"
2830
#include "spi.h"

tmk_core/protocol/arm_atsam/clks.c

+21-69
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
2121

2222
volatile clk_t system_clks;
2323
volatile uint64_t ms_clk;
24-
25-
volatile uint8_t us_delay_done;
24+
uint32_t usec_delay_mult;
25+
#define USEC_DELAY_LOOP_CYCLES 3 //Sum of instruction cycles in us delay loop
2626

2727
const uint32_t sercom_apbbase[] = {(uint32_t)SERCOM0,(uint32_t)SERCOM1,(uint32_t)SERCOM2,(uint32_t)SERCOM3,(uint32_t)SERCOM4,(uint32_t)SERCOM5};
2828
const uint8_t sercom_pchan[] = {7, 8, 23, 24, 34, 35};
@@ -73,6 +73,9 @@ void CLK_oscctrl_init(void)
7373

7474
system_clks.freq_gclk[0] = system_clks.freq_dpll[0];
7575

76+
usec_delay_mult = system_clks.freq_gclk[0] / (USEC_DELAY_LOOP_CYCLES * 1000000);
77+
if (usec_delay_mult < 1) usec_delay_mult = 1; //Never allow a multiplier of zero
78+
7679
DBGC(DC_CLK_OSC_INIT_COMPLETE);
7780
}
7881

@@ -158,23 +161,11 @@ void TC4_Handler()
158161
}
159162
}
160163

161-
void TC5_Handler()
162-
{
163-
if (TC5->COUNT16.INTFLAG.bit.MC0)
164-
{
165-
TC5->COUNT16.INTFLAG.reg = TC_INTENCLR_MC0;
166-
us_delay_done = 1;
167-
TC5->COUNT16.CTRLA.bit.ENABLE = 0;
168-
while (TC5->COUNT16.SYNCBUSY.bit.ENABLE) {}
169-
}
170-
}
171-
172164
uint32_t CLK_enable_timebase(void)
173165
{
174166
Gclk *pgclk = GCLK;
175167
Mclk *pmclk = MCLK;
176168
Tc *ptc4 = TC4;
177-
Tc *ptc5 = TC5;
178169
Tc *ptc0 = TC0;
179170
Evsys *pevsys = EVSYS;
180171

@@ -189,11 +180,6 @@ uint32_t CLK_enable_timebase(void)
189180
pgclk->PCHCTRL[TC4_GCLK_ID].bit.GEN = GEN_TC45;
190181
pgclk->PCHCTRL[TC4_GCLK_ID].bit.CHEN = 1;
191182

192-
//unmask TC5 sourcegclk2 to TC5
193-
pmclk->APBCMASK.bit.TC5_ = 1;
194-
pgclk->PCHCTRL[TC5_GCLK_ID].bit.GEN = GEN_TC45;
195-
pgclk->PCHCTRL[TC5_GCLK_ID].bit.CHEN = 1;
196-
197183
//configure TC4
198184
DBGC(DC_CLK_ENABLE_TIMEBASE_TC4_BEGIN);
199185
ptc4->COUNT16.CTRLA.bit.ENABLE = 0;
@@ -220,30 +206,6 @@ uint32_t CLK_enable_timebase(void)
220206

221207
DBGC(DC_CLK_ENABLE_TIMEBASE_TC4_COMPLETE);
222208

223-
//configure TC5
224-
DBGC(DC_CLK_ENABLE_TIMEBASE_TC5_BEGIN);
225-
ptc5->COUNT16.CTRLA.bit.ENABLE = 0;
226-
while (ptc5->COUNT16.SYNCBUSY.bit.ENABLE) { DBGC(DC_CLK_ENABLE_TIMEBASE_TC5_SYNC_DISABLE); }
227-
ptc5->COUNT16.CTRLA.bit.SWRST = 1;
228-
while (ptc5->COUNT16.SYNCBUSY.bit.SWRST) { DBGC(DC_CLK_ENABLE_TIMEBASE_TC5_SYNC_SWRST_1); }
229-
while (ptc5->COUNT16.CTRLA.bit.SWRST) { DBGC(DC_CLK_ENABLE_TIMEBASE_TC5_SYNC_SWRST_2); }
230-
231-
//CTRLA defaults
232-
//CTRLB as default, counting up
233-
ptc5->COUNT16.CTRLBCLR.reg = 5;
234-
while (ptc5->COUNT16.SYNCBUSY.bit.CTRLB) { DBGC(DC_CLK_ENABLE_TIMEBASE_TC5_SYNC_CLTRB); }
235-
//ptc5->COUNT16.DBGCTRL.bit.DBGRUN = 1;
236-
237-
//wave mode
238-
ptc5->COUNT16.WAVE.bit.WAVEGEN = 1; //MFRQ match frequency mode, toggle each CC match
239-
//generate event for next stage
240-
ptc5->COUNT16.EVCTRL.bit.MCEO0 = 1;
241-
242-
NVIC_EnableIRQ(TC5_IRQn);
243-
ptc5->COUNT16.INTENSET.bit.MC0 = 1;
244-
245-
DBGC(DC_CLK_ENABLE_TIMEBASE_TC5_COMPLETE);
246-
247209
//unmask TC0,1, sourcegclk2 to TC0,1
248210
pmclk->APBAMASK.bit.TC0_ = 1;
249211
pgclk->PCHCTRL[TC0_GCLK_ID].bit.GEN = GEN_TC45;
@@ -289,37 +251,27 @@ uint32_t CLK_enable_timebase(void)
289251
return 0;
290252
}
291253

292-
uint32_t CLK_get_ms(void)
254+
void CLK_delay_us(uint32_t usec)
293255
{
294-
return ms_clk;
295-
}
296-
297-
void CLK_delay_us(uint16_t usec)
298-
{
299-
us_delay_done = 0;
300-
301-
if (TC5->COUNT16.CTRLA.bit.ENABLE)
302-
{
303-
TC5->COUNT16.CTRLA.bit.ENABLE = 0;
304-
while (TC5->COUNT16.SYNCBUSY.bit.ENABLE) {}
305-
}
306-
307-
if (usec < 10) usec = 0;
308-
else usec -= 10;
309-
310-
TC5->COUNT16.CC[0].reg = usec;
311-
while (TC5->COUNT16.SYNCBUSY.bit.CC0) {}
312-
313-
TC5->COUNT16.CTRLA.bit.ENABLE = 1;
314-
while (TC5->COUNT16.SYNCBUSY.bit.ENABLE) {}
315-
316-
while (!us_delay_done) {}
256+
asm (
257+
"CBZ R0, return\n\t" //If usec == 0, branch to return label
258+
);
259+
asm (
260+
"MULS R0, %0\n\t" //Multiply R0(usec) by usec_delay_mult and store in R0
261+
".balign 16\n\t" //Ensure loop is aligned for fastest performance
262+
"loop: SUBS R0, #1\n\t" //Subtract 1 from R0 and update flags (1 cycle)
263+
"BNE loop\n\t" //Branch if non-zero to loop label (2 cycles) NOTE: USEC_DELAY_LOOP_CYCLES is the sum of loop cycles
264+
"return:\n\t" //Return label
265+
: //No output registers
266+
: "r" (usec_delay_mult) //For %0
267+
);
268+
//Note: BX LR generated
317269
}
318270

319271
void CLK_delay_ms(uint64_t msec)
320272
{
321-
msec += CLK_get_ms();
322-
while (msec > CLK_get_ms()) {}
273+
msec += timer_read64();
274+
while (msec > timer_read64()) {}
323275
}
324276

325277
void clk_enable_sercom_apbmask(int sercomn)

tmk_core/protocol/arm_atsam/clks.h

+2-3
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,8 @@ void CLK_oscctrl_init(void);
7777
void CLK_reset_time(void);
7878
uint32_t CLK_set_gclk_freq(uint8_t gclkn, uint32_t freq);
7979
uint32_t CLK_enable_timebase(void);
80-
uint32_t CLK_get_ms(void);
81-
uint64_t CLK_get_us(void);
82-
void CLK_delay_us(uint16_t usec);
80+
uint64_t timer_read64(void);
81+
void CLK_delay_us(uint32_t usec);
8382
void CLK_delay_ms(uint64_t msec);
8483

8584
uint32_t CLK_set_spi_freq(uint8_t sercomn, uint32_t freq);

tmk_core/protocol/arm_atsam/i2c_master.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -265,12 +265,12 @@ uint8_t I2C3733_Init_Control(void)
265265
//USB state machine will enable driver when communication is ready
266266
I2C3733_Control_Set(0);
267267

268-
CLK_delay_ms(1);
268+
wait_ms(1);
269269

270270
sr_exp_data.bit.IRST = 0;
271271
SR_EXP_WriteData();
272272

273-
CLK_delay_ms(1);
273+
wait_ms(1);
274274

275275
DBGC(DC_I2C3733_INIT_CONTROL_COMPLETE);
276276

tmk_core/protocol/arm_atsam/led_matrix.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -494,11 +494,11 @@ void led_matrix_task(void)
494494
if (led_enabled)
495495
{
496496
//If an update may run and frame processing has completed
497-
if (CLK_get_ms() >= led_next_run && led_cur == lede)
497+
if (timer_read64() >= led_next_run && led_cur == lede)
498498
{
499499
uint8_t drvid;
500500

501-
led_next_run = CLK_get_ms() + LED_UPDATE_RATE; //Set next frame update time
501+
led_next_run = timer_read64() + LED_UPDATE_RATE; //Set next frame update time
502502

503503
//NOTE: GCR does not need to be timed with LED processing, but there is really no harm
504504
if (gcr_actual != gcr_actual_last)

tmk_core/protocol/arm_atsam/main_arm_atsam.c

+9-9
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ void send_consumer(uint16_t data)
159159

160160
void main_subtask_usb_state(void)
161161
{
162-
static uint32_t fsmstate_on_delay = 0; //Delay timer to be sure USB is actually operating before bringing up hardware
162+
static uint64_t fsmstate_on_delay = 0; //Delay timer to be sure USB is actually operating before bringing up hardware
163163
uint8_t fsmstate_now = USB->DEVICE.FSMSTATUS.reg; //Current state from hardware register
164164

165165
if (fsmstate_now == USB_FSMSTATUS_FSMSTATE_SUSPEND_Val) //If USB SUSPENDED
@@ -188,9 +188,9 @@ void main_subtask_usb_state(void)
188188
{
189189
if (fsmstate_on_delay == 0) //If ON delay timer is cleared
190190
{
191-
fsmstate_on_delay = CLK_get_ms() + 250; //Set ON delay timer
191+
fsmstate_on_delay = timer_read64() + 250; //Set ON delay timer
192192
}
193-
else if (CLK_get_ms() > fsmstate_on_delay) //Else if ON delay timer is active and timed out
193+
else if (timer_read64() > fsmstate_on_delay) //Else if ON delay timer is active and timed out
194194
{
195195
suspend_wakeup_init(); //Run wakeup routine
196196
g_usb_state = fsmstate_now; //Save current USB state
@@ -214,9 +214,9 @@ void main_subtask_power_check(void)
214214
{
215215
static uint64_t next_5v_checkup = 0;
216216

217-
if (CLK_get_ms() > next_5v_checkup)
217+
if (timer_read64() > next_5v_checkup)
218218
{
219-
next_5v_checkup = CLK_get_ms() + 5;
219+
next_5v_checkup = timer_read64() + 5;
220220

221221
v_5v = adc_get(ADC_5V);
222222
v_5v_avg = 0.9 * v_5v_avg + 0.1 * v_5v;
@@ -229,9 +229,9 @@ void main_subtask_usb_extra_device(void)
229229
{
230230
static uint64_t next_usb_checkup = 0;
231231

232-
if (CLK_get_ms() > next_usb_checkup)
232+
if (timer_read64() > next_usb_checkup)
233233
{
234-
next_usb_checkup = CLK_get_ms() + 10;
234+
next_usb_checkup = timer_read64() + 10;
235235

236236
USB_HandleExtraDevice();
237237
}
@@ -325,9 +325,9 @@ int main(void)
325325
keyboard_task();
326326

327327
#ifdef CONSOLE_ENABLE
328-
if (CLK_get_ms() > next_print)
328+
if (timer_read64() > next_print)
329329
{
330-
next_print = CLK_get_ms() + 250;
330+
next_print = timer_read64() + 250;
331331
//Add any debug information here that you want to see very often
332332
//dprintf("5v=%u 5vu=%u dlow=%u dhi=%u gca=%u gcd=%u\r\n", v_5v, v_5v_avg, v_5v_avg - V5_LOW, v_5v_avg - V5_HIGH, gcr_actual, gcr_desired);
333333
}

0 commit comments

Comments
 (0)