Skip to content

Instantly share code, notes, and snippets.

@tspspi

tspspi/sysclk.c Secret

Created July 25, 2021 20:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tspspi/b4403cfd678620ef30e743374fe5e547 to your computer and use it in GitHub Desktop.
Save tspspi/b4403cfd678620ef30e743374fe5e547 to your computer and use it in GitHub Desktop.
A simple timekeeping module for AVRs
#include "./sysclk.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
System tick timer
*/
volatile unsigned long int systemMillis = 0;
volatile unsigned long int systemMilliFractional = 0;
volatile unsigned long int systemMonotonicOverflowCnt = 0;
ISR(TIMER0_OVF_vect) {
unsigned long int m, f;
m = systemMillis;
f = systemMilliFractional;
m = m + SYSCLK_MILLI_INCREMENT;
f = f + SYSCLK_MILLIFRACT_INCREMENT;
if(f >= SYSCLK_MILLIFRACT_MAXIMUM) {
f = f - SYSCLK_MILLIFRACT_MAXIMUM;
m = m + 1;
}
systemMonotonicOverflowCnt = systemMonotonicOverflowCnt + 1;
systemMillis = m;
systemMilliFractional = f;
}
unsigned long int millis() {
unsigned long int m;
uint8_t srOld = SREG;
cli();
m = systemMillis;
SREG = srOld;
return m;
}
unsigned long int micros() {
uint8_t srOld = SREG;
unsigned long int overflowCounter;
unsigned long int timerCounter;
cli();
overflowCounter = systemMonotonicOverflowCnt;
timerCounter = TCNT0;
if(((TIFR0 & 0x01) != 0) && (timerCounter < 255)) {
overflowCounter = overflowCounter + 1;
}
SREG = srOld;
return ((overflowCounter << 8) + timerCounter) * (64L / (F_CPU / 1000000L));
}
void delay(unsigned long millisecs) {
unsigned int lastMicro;
lastMicro = (unsigned int)micros();
while(millisecs > 0) {
unsigned int curMicro = micros();
if(curMicro - lastMicro >= 1000) {
lastMicro = lastMicro + 1000;
millisecs = millisecs - 1;
}
}
return;
}
void delayMicros(unsigned int microDelay) {
#if F_CPU == 20000000L
__asm__ __volatile__ (
"nop\n"
"nop\n"
);
if((microDelay = microDelay - 1) == 0) {
return;
}
microDelay = (microDelay << 2) + microDelay;
#elif F_CPU == 16000000L
if((microDelay = microDelay - 1) == 0) {
return;
}
microDelay = (microDelay << 2) - 2;
#elif F_CPU == 8000000L
if((microDelay = microDelay - 1) == 0) {
return;
}
if((microDelay = microDelay - 1) == 0) {
return;
}
microDelay = (microDelay << 1) - 1;
#else
#error No known delay loop calibration available for this F_CPU
#endif
__asm__ __volatile__ (
"lp: sbiw %0, 1\n"
" brne lp"
: "=w" (microDelay)
: "0" (microDelay)
);
return;
}
void systickInit() {
uint8_t sregOld = SREG;
cli();
TCCR0A = 0x00;
TCCR0B = 0x03; /* /64 prescaler */
TIMSK0 = 0x01; /* Enable overflow interrupt */
PRR = PRR & (~0x20);
SREG = sregOld;
}
void systickDisable() {
TIMSK0 = 0x00;
}
#ifdef __cplusplus
} /* extern "C" { */
#endif
#include <avr/io.h>
#include <avr/interrupt.h>
#include <math.h>
#include <util/twi.h>
#include <stdint.h>
#define SYSCLK_TIMER_OVERFLOW_MICROS (64L * ((256L * 1000000L) / F_CPU))
#define SYSCLK_MILLI_INCREMENT (SYSCLK_TIMER_OVERFLOW_MICROS / 1000L)
#define SYSCLK_MILLIFRACT_INCREMENT ((SYSCLK_TIMER_OVERFLOW_MICROS % 1000L) >> 3)
#define SYSCLK_MILLIFRACT_MAXIMUM (1000 >> 3)
#ifdef __cplusplus
extern "C" {
#endif
void systickInit();
void systickDisable();
unsigned long int millis();
unsigned long int micros();
void delay(unsigned long millisecs);
void delayMicros(unsigned int microDelay);
#ifdef __cplusplus
} /* extern "C" { */
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment