Last active
May 26, 2020 00:23
-
-
Save DaelonSuzuka/38d835392babca9947c215fafbb0158e to your computer and use it in GitHub Desktop.
System Time Files
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef _CONFIG_H_ | |
#define _CONFIG_H_ | |
/* ************************************************************************** */ | |
// CONFIG1L | |
#pragma config FEXTOSC = OFF // External Oscillator Selection->Oscillator not enabled | |
#pragma config RSTOSC = HFINTOSC_64MHZ // Reset Oscillator Selection->HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1 | |
// CONFIG1H | |
#pragma config CLKOUTEN = OFF // Clock out Enable bit->CLKOUT function is disabled | |
#pragma config PR1WAY = OFF // PRLOCKED One-Way Set Enable bit->PRLOCK bit can be set and cleared repeatedly | |
#pragma config CSWEN = ON // Clock Switch Enable bit->Writing to NOSC and NDIV is allowed | |
#pragma config FCMEN = ON // Fail-Safe Clock Monitor Enable bit->Fail-Safe Clock Monitor enabled | |
// CONFIG2L | |
#pragma config MCLRE = INTMCLR // MCLR Enable bit->If LVP = 0, MCLR pin function is port defined function; If LVP =1, RE3 pin fuction is MCLR | |
#pragma config PWRTS = PWRT_OFF // Power-up timer selection bits->PWRT is disabled | |
#pragma config MVECEN = ON // Multi-vector enable bit->Interrupt contoller does not use vector table to prioritze interrupts | |
#pragma config IVT1WAY = OFF // IVTLOCK bit One-way set enable bit->IVTLOCK bit can be cleared and set repeatedly | |
#pragma config LPBOREN = OFF // Low Power BOR Enable bit->ULPBOR disabled | |
#pragma config BOREN = SBORDIS // Brown-out Reset Enable bits->Brown-out Reset enabled , SBOREN bit is ignored | |
// CONFIG2H | |
#pragma config BORV = VBOR_2P45 // Brown-out Reset Voltage Selection bits->Brown-out Reset Voltage (VBOR) set to 2.45V | |
#pragma config ZCD = OFF // ZCD Disable bit->ZCD disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON | |
#pragma config PPS1WAY = OFF // PPSLOCK bit One-Way Set Enable bit->PPSLOCK bit can be set and cleared repeatedly (subject to the unlock sequence) | |
#pragma config STVREN = ON // Stack Full/Underflow Reset Enable bit->Stack full/underflow will cause Reset | |
#pragma config DEBUG = OFF // Debugger Enable bit->Background debugger disabled | |
#pragma config XINST = OFF // Extended Instruction Set Enable bit->Extended Instruction Set and Indexed Addressing Mode disabled | |
// CONFIG3L | |
#pragma config WDTCPS = WDTCPS_31 // WDT Period selection bits->Divider ratio 1:65536; software control of WDTPS | |
#pragma config WDTE = OFF // WDT operating mode->WDT Disabled; SWDTEN is ignored | |
// CONFIG3H | |
#pragma config WDTCWS = WDTCWS_7 // WDT Window Select bits->window always open (100%); software control; keyed access not required | |
#pragma config WDTCCS = SC // WDT input clock selector->Software Control | |
// CONFIG4L | |
#pragma config BBSIZE = BBSIZE_512 // Boot Block Size selection bits->Boot Block size is 512 words | |
#pragma config BBEN = OFF // Boot Block enable bit->Boot block disabled | |
#pragma config SAFEN = OFF // Storage Area Flash enable bit->SAF disabled | |
#pragma config WRTAPP = OFF // Application Block write protection bit->Application Block not write protected | |
// CONFIG4H | |
#pragma config WRTB = OFF // Configuration Register Write Protection bit->Configuration registers (300000-30000Bh) not write-protected | |
#pragma config WRTC = OFF // Boot Block Write Protection bit->Boot Block (000000-0007FFh) not write-protected | |
#pragma config WRTD = OFF // Data EEPROM Write Protection bit->Data EEPROM not write-protected | |
#pragma config WRTSAF = OFF // SAF Write protection bit->SAF not Write Protected | |
#pragma config LVP = OFF // Low Voltage Programming Enable bit->HV on MCLR/VPP must be used for programming | |
// CONFIG5L | |
#pragma config CP = OFF // PFM and Data EEPROM Code Protection bit->PFM and Data EEPROM code protection disabled | |
#endif |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "system_time.h" | |
#include "timer.h" | |
#include <xc8.h> | |
/* ************************************************************************** */ | |
// SMT helper macros | |
#define SMT_enable() SMT1CON0bits.EN = 1 | |
#define SMT_disable() SMT1CON0bits.EN = 0 | |
#define SMT_start() SMT1CON1bits.GO = 1 | |
#define SMT_stop() SMT1CON1bits.GO = 0 | |
#define SMT_clear() SMT1TMR = 0 | |
#define SMT_interrupt_enable() PIE1bits.SMT1IE = 1 | |
#define SMT_interrupt_disable() PIE1bits.SMT1IE = 0 | |
#define SMT_mode(mode) SMT1CON1bits.MODE = mode | |
#define SMT_MODE_COUNTER 0b1000 | |
#define SMT_signal(source) SMT1SIGbits.SSEL = source | |
#define SMT_SIGNAL_TMR2 0b00011 | |
#define SMT_latch_now() SMT1STATbits.CPRUP = 1 | |
void system_time_init(void) { | |
// set timer2 to overflow in exactly 1mS | |
timer2_clock_source(TMR_CLK_FOSC); | |
timer2_prescale(TMR_PRE_1_128); | |
timer2_postscale(TMR_POST_1_2); | |
timer2_period_set(0xF9); | |
timer2_start(); | |
// set Signal Measurement Timer to count the number of timer2 overflows | |
SMT_mode(SMT_MODE_COUNTER); | |
SMT_signal(SMT_SIGNAL_TMR2); | |
SMT_clear(); | |
SMT_enable(); | |
SMT_start(); | |
SMT_interrupt_enable(); | |
} | |
/* -------------------------------------------------------------------------- */ | |
static volatile uint8_t smtOverflowCount; | |
void __interrupt(irq(SMT1), high_priority) SMT_overflow_ISR() { | |
PIR1bits.SMT1IF = 0; // clear SMT interrupt flag | |
smtOverflowCount++; | |
} | |
/* -------------------------------------------------------------------------- */ | |
/* Notes on reading the Signal Measurement Timer | |
The SMT is a 24 bit counter, whose value is stored in three registers: | |
SMT1TMRL | |
SMT1TMRH | |
SMT1TMRU | |
This means that reading the value of the SMT is very far from an atomic | |
operation. The processor provides a tool to solve this problem in the form | |
of three SMT Captured Period Registers: | |
SMT1CPRL | |
SMT1CPRH | |
SMT1CPRU | |
When SMT1STATbits.CPRUP is set, the value of SMT1TMR is snapshotted into | |
SMT1CPR, and therefore is safe to read without worrying about corrupted | |
data. | |
*/ | |
system_time_t get_current_time(void) { | |
SMT_interrupt_disable(); | |
SMT_latch_now(); | |
system_time_t currentTime = smtOverflowCount; | |
currentTime <<= 24; | |
currentTime += SMT1CPR; | |
SMT_interrupt_enable(); | |
return currentTime; | |
} | |
/* -------------------------------------------------------------------------- */ | |
void delay_us(uint16_t microSeconds) { | |
while (microSeconds--) { | |
asm("nop"); | |
asm("nop"); | |
asm("nop"); | |
asm("nop"); | |
asm("nop"); | |
asm("nop"); | |
asm("nop"); | |
asm("nop"); | |
asm("nop"); | |
asm("nop"); | |
} | |
} | |
void delay_ms(system_time_t milliSeconds) { | |
system_time_t startTime = get_current_time(); | |
while (time_since(startTime) < milliSeconds) { | |
// empty loop | |
} | |
} | |
/* ************************************************************************** */ | |
#include "os/shell/shell_command_utils.h" | |
// | |
#define CLOCK_CHECK_COOLDOWN 1000 | |
int8_t clockmon_callback(char currentChar) { | |
static system_time_t lastAttempt = 0; | |
if (time_since(lastAttempt) < CLOCK_CHECK_COOLDOWN) { | |
return 0; | |
} | |
lastAttempt = get_current_time(); | |
printf("[%lu] \r\n", get_current_time()); | |
return 0; | |
} | |
// setup | |
void sh_clockmon(int argc, char **argv) { | |
println("entering clockmon"); | |
shell_register_callback(clockmon_callback); | |
} | |
REGISTER_SHELL_COMMAND(sh_clockmon, "clockmon"); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef _SYSTEM_TIME_H_ | |
#define _SYSTEM_TIME_H_ | |
#include <stdint.h> | |
/* ************************************************************************** */ | |
/* Notes on using the System Tick module | |
This module counts the system's uptime in milliseconds. It functions | |
similarly to the millis() function from the Arduino platform. | |
There are several differences between millis() and get_current_time(): | |
millis() stores its count in a uint32_t, meaning it takes roughly 49 days | |
for millis() to overflow. get_current_time() stores its count in a uint24_t, | |
meaning it takes roughly 4.6 hours to overflow. | |
millis() requires an interrupt to fire every millisecond, and an ISR that | |
increments a 4-byte-long uint32_t. This is a very quick ISR, but it's less | |
than ideal that this ISR will need to be running all the time, behind any | |
other operations you intend to do on your system. get_current_time() uses no | |
interrupt, so it still counts time during critical sections of code and will | |
never contribute to interrupt-based timer bugs. | |
This module uses several hardware features of the K42. One hardware timer of | |
any variety needs to be configured to overflow every millisecond. | |
This timer is then configured as the clock source of the Signal Measurement | |
Timer, a special 24-bit counter. This causes the SMT to increment once every | |
millisecond, completely in the background. No interrupts are necessary to | |
count time. | |
The SMT has another special feature that assists with read operations. | |
Manipulating a 24-bit value on an 8-bit system takes several operations, | |
potentially causing data corruption if the register value changes in the | |
middle of a read. The SMT1STAT register has a bit that causes the SMT count | |
register to be copied to a buffer, which can then be read from without | |
worrying about atomic access. | |
Maximum countable time: | |
UINT24_MAX = 16,777,216 ticks until overflow | |
Each tick = 1 millisecond: | |
16,777,216 / 1000 = 16,777.216 seconds | |
16,777 / 60 = 279.6 minutes | |
279 minutes / 60 = 4.6 hours until overflow | |
*/ | |
/* ************************************************************************** */ | |
typedef uint32_t system_time_t; | |
/* ************************************************************************** */ | |
// setup | |
extern void system_time_init(void); | |
/* -------------------------------------------------------------------------- */ | |
// returns the number of milliseconds since boot | |
extern system_time_t get_current_time(void); | |
// time_since() returns the time | |
#define time_since(startTime) (get_current_time() - startTime) | |
/* -------------------------------------------------------------------------- */ | |
// delay_us() uses NOPs to wait n microseconds, to an accuracy of +-2% | |
extern void delay_us(uint16_t microSeconds); | |
/* delay_ms() uses the system tick to wait between n-1 and n milliseconds. | |
This error is caused by the 1ms resolution of the systick. delay_ms() can | |
start anywhere in the 'current' ms. Calling delay_ms() with arguments less | |
than 10 can result in ~(1/(n+1))% error, as the jitter becomes a larger and | |
larger fraction of the desired wait time. | |
If a high-accuracy delay is required, please use delay_us() instead. | |
*/ | |
extern void delay_ms(system_time_t milliSeconds); | |
#endif |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef _TIMER_H_ | |
#define _TIMER_H_ | |
#include <stdint.h> | |
#include <xc8.h> | |
/* ************************************************************************** */ | |
// Setup | |
#define timer0_clock_source(value) T0CON1bits.CS = value | |
#define timer0_prescale(value) T0CON1bits.CKPS = value | |
#define timer0_postscale(value) T0CON0bits.OUTPS = value | |
#define timer0_clock_sync_enable() T0CON1bits.ASYNC = 1 | |
#define timer0_clock_sync_disable() T0CON1bits.ASYNC = 0 | |
// General manipulation | |
#define timer0_start() TIMER0_ON = 1 | |
#define timer0_stop() TIMER0_ON = 0 | |
#define timer0_clear() \ | |
do { \ | |
TMR0H = 0x00; \ | |
TMR0L = 0x00; \ | |
} while (0) | |
#define timer0_read() (((uint16_t)TMR0H << 8) | (uint16_t)TMR0L) | |
// Interrupt control | |
#define timer0_interrupt_enable() TIMER0_IE = 1 | |
#define timer0_interrupt_disable() TIMER0_IE = 0 | |
#define timer0_IF_clear() TIMER0_IF = 0 | |
#define timer0_IF_read() TIMER0_IF | |
// Other features | |
#define timer0_period_set(value) TMR0H = value // only in 8bit mode | |
/* -------------------------------------------------------------------------- */ | |
// Setup | |
#define timer1_clock_source(value) T1CLK = value | |
#define timer1_prescale(value) T1CONbits.CKPS = value | |
#define timer1_clock_sync_enable() T1CONbits.NOT_SYNC = 0 | |
#define timer1_clock_sync_disable() T1CONbits.NOT_SYNC = 1 | |
// General manipulation | |
#define timer1_start() TIMER1_ON = 1 | |
#define timer1_stop() TIMER1_ON = 0 | |
#define timer1_clear() \ | |
do { \ | |
TMR1H = 0x00; \ | |
TMR1L = 0x00; \ | |
} while (0) | |
#define timer1_read() (((uint16_t)TMR1H << 8) | (uint16_t)TMR1L) | |
// Interrupt control | |
#define timer1_interrupt_enable() TIMER1_IE = 1 | |
#define timer1_interrupt_disable() TIMER1_IE = 0 | |
#define timer1_IF_clear() TIMER1_IF = 0 | |
#define timer1_IF_read() TIMER1_IF | |
// Other features | |
#define timer1_gate_enable() TIMER1_GATE_EN = 1 | |
#define timer1_gate_disable() TIMER1_GATE_EN = 0 | |
/* -------------------------------------------------------------------------- */ | |
// Setup | |
#define timer2_clock_source(value) T2CLK = value | |
#define timer2_prescale(value) T2CONbits.CKPS = value | |
#define timer2_postscale(value) T2CONbits.OUTPS = value | |
// General manipulation | |
#define timer2_start() TIMER2_ON = 1 | |
#define timer2_stop() TIMER2_ON = 0 | |
#define timer2_clear() TMR2 = 0x00; | |
#define timer2_read() TMR2 | |
// Interrupt control | |
#define timer2_interrupt_enable() TIMER2_IE = 1 | |
#define timer2_interrupt_disable() TIMER2_IE = 0 | |
#define timer2_IF_clear() TIMER2_IF = 0 | |
#define timer2_IF_read() TIMER2_IF | |
// Other features | |
#define timer2_period_set(value) PR2 = value | |
/* -------------------------------------------------------------------------- */ | |
// Setup | |
#define timer3_clock_source(value) T3CLK = value | |
#define timer3_prescale(value) T3CONbits.CKPS = value | |
#define timer3_clock_sync_enable() T3CONbits.NOT_SYNC = 0 | |
#define timer3_clock_sync_disable() T3CONbits.NOT_SYNC = 1 | |
// General manipulation | |
#define timer3_start() TIMER3_ON = 1 | |
#define timer3_stop() TIMER3_ON = 0 | |
#define timer3_clear() \ | |
do { \ | |
TMR3H = 0x00; \ | |
TMR3L = 0x00; \ | |
} while (0) | |
#define timer3_read() (((uint16_t)TMR3H << 8) | (uint16_t)TMR3L) | |
// Interrupt control | |
#define timer3_interrupt_enable() TIMER3_IE = 1 | |
#define timer3_interrupt_disable() TIMER3_IE = 0 | |
#define timer3_IF_clear() TIMER3_IF = 0 | |
#define timer3_IF_read() TIMER3_IF | |
// Other features | |
#define timer3_gate_enable() TIMER3_GATE_EN = 1 | |
#define timer3_gate_disable() TIMER3_GATE_EN = 0 | |
/* -------------------------------------------------------------------------- */ | |
// Setup | |
#define timer4_clock_source(value) T4CLK = value | |
#define timer4_prescale(value) T4CONbits.CKPS = value | |
#define timer4_postscale(value) T4CONbits.OUTPS = value | |
// General manipulation | |
#define timer4_start() TIMER4_ON = 1 | |
#define timer4_stop() TIMER4_ON = 0 | |
#define timer4_clear() TMR4 = 0x00; | |
#define timer4_read() TMR4 | |
// Interrupt control | |
#define timer4_interrupt_enable() TIMER4_IE = 1 | |
#define timer4_interrupt_disable() TIMER4_IE = 0 | |
#define timer4_IF_clear() TIMER4_IF = 0 | |
#define timer4_IF_read() TIMER4_IF | |
// Other features | |
#define timer4_period_set(value) PR4 = value | |
/* -------------------------------------------------------------------------- */ | |
// Setup | |
#define timer5_clock_source(value) T5CLK = value | |
#define timer5_prescale(value) T5CONbits.CKPS = value | |
#define timer5_clock_sync_enable() T5CONbits.NOT_SYNC = 0 | |
#define timer5_clock_sync_disable() T5CONbits.NOT_SYNC = 1 | |
// General manipulation | |
#define timer5_start() TIMER5_ON = 1 | |
#define timer5_stop() TIMER5_ON = 0 | |
#define timer5_clear() \ | |
do { \ | |
TMR5H = 0x00; \ | |
TMR5L = 0x00; \ | |
} while (0) | |
#define timer5_read() (((uint16_t)TMR5H << 8) | (uint16_t)TMR5L) | |
// Interrupt control | |
#define timer5_interrupt_enable() TIMER5_IE = 1 | |
#define timer5_interrupt_disable() TIMER5_IE = 0 | |
#define timer5_IF_clear() TIMER5_IF = 0 | |
#define timer5_IF_read() TIMER5_IF | |
// Other features | |
#define timer5_gate_enable() TIMER5_GATE_EN = 1 | |
#define timer5_gate_disable() TIMER5_GATE_EN = 0 | |
/* -------------------------------------------------------------------------- */ | |
// Setup | |
#define timer6_clock_source(value) T6CLK = value | |
#define timer6_prescale(value) T6CONbits.CKPS = value | |
#define timer6_postscale(value) T6CONbits.OUTPS = value | |
// General manipulation | |
#define timer6_start() TIMER6_ON = 1 | |
#define timer6_stop() TIMER6_ON = 0 | |
#define timer6_clear() TMR6 = 0x00; | |
#define timer6_read() TMR6 | |
// Interrupt control | |
#define timer6_interrupt_enable() TIMER6_IE = 1 | |
#define timer6_interrupt_disable() TIMER6_IE = 0 | |
#define timer6_IF_clear() TIMER6_IF = 0 | |
#define timer6_IF_read() TIMER6_IF | |
// Other features | |
#define timer6_period_set(value) PR6 = value | |
/* ************************************************************************** */ | |
// Timer X Interrupt Flag bit | |
#define TIMER0_IF PIR3bits.TMR0IF | |
#define TIMER1_IF PIR4bits.TMR1IF | |
#define TIMER2_IF PIR4bits.TMR2IF | |
#define TIMER3_IF PIR6bits.TMR3IF | |
#define TIMER4_IF PIR7bits.TMR4IF | |
#define TIMER5_IF PIR8bits.TMR5IF | |
#define TIMER6_IF PIR9bits.TMR6IF | |
// Timer X Interrupt Enable bit | |
#define TIMER0_IE PIE3bits.TMR0IE | |
#define TIMER1_IE PIE4bits.TMR1IE | |
#define TIMER2_IE PIE4bits.TMR2IE | |
#define TIMER3_IE PIE6bits.TMR3IE | |
#define TIMER4_IE PIE7bits.TMR4IE | |
#define TIMER5_IE PIE8bits.TMR5IE | |
#define TIMER6_IE PIE9bits.TMR6IE | |
// Timer X start bit | |
#define TIMER0_ON T0CON0bits.EN | |
#define TIMER1_ON T1CONbits.ON | |
#define TIMER2_ON T2CONbits.ON | |
#define TIMER3_ON T3CONbits.ON | |
#define TIMER4_ON T4CONbits.ON | |
#define TIMER5_ON T5CONbits.ON | |
#define TIMER6_ON T6CONbits.ON | |
// Timer 1/3/5 Gate Enable bit | |
#define TIMER1_GATE_EN T1GCONbits.GE | |
#define TIMER3_GATE_EN T3GCONbits.GE | |
#define TIMER5_GATE_EN T5GCONbits.GE | |
/* ************************************************************************** */ | |
// Timer 1/2/3/4/5/6 clock sources - not comprehensive | |
#define TMR_CLK_PPS 0 | |
#define TMR_CLK_FOSC4 1 | |
#define TMR_CLK_FOSC 2 | |
#define TMR_CLK_HFINTOSC 3 | |
#define TMR_CLK_LFINTOSC 4 | |
#define TMR_CLK_MFINTOSC_500_K 5 | |
#define TMR_CLK_MFINTOSC_32_K 6 | |
#define TMR_CLK_SOSC 7 | |
#define TMR_CLK_CLKREF 8 | |
#define TMR_CLK_CLC1 13 | |
#define TMR_CLK_CLC2 14 | |
#define TMR_CLK_CLC3 15 | |
#define TMR_CLK_CLC4 16 | |
// Timer 0 clock sources | |
#define TMR0_CLK_PPS 0 | |
#define TMR0_CLK_PPS_INVERTED 1 | |
#define TMR0_CLK_FOSC4 2 | |
#define TMR0_CLK_HFINTOSC 3 | |
#define TMR0_CLK_LFINTOSC 4 | |
#define TMR0_CLK_MFINTOSC_500_K 5 | |
#define TMR0_CLK_SOSC 6 | |
#define TMR0_CLK_CLC1 7 | |
/* -------------------------------------------------------------------------- */ | |
// Shared timer prescale values | |
#define TMR_PRE_1_1 0 | |
#define TMR_PRE_1_2 1 | |
#define TMR_PRE_1_4 2 | |
#define TMR_PRE_1_8 3 | |
// Timer 0/2/4/6 prescale values | |
#define TMR_PRE_1_16 4 | |
#define TMR_PRE_1_32 5 | |
#define TMR_PRE_1_64 6 | |
#define TMR_PRE_1_128 7 | |
// Timer 0 prescale values | |
#define TMR_PRE_1_256 8 | |
#define TMR_PRE_1_512 9 | |
#define TMR_PRE_1_1024 10 | |
#define TMR_PRE_1_2048 11 | |
#define TMR_PRE_1_4096 12 | |
#define TMR_PRE_1_8192 13 | |
#define TMR_PRE_1_16384 14 | |
#define TMR_PRE_1_32768 15 | |
/* -------------------------------------------------------------------------- */ | |
// Timer 0/2/4/6 postscale values | |
#define TMR_POST_1_1 0 | |
#define TMR_POST_1_2 1 | |
#define TMR_POST_1_3 2 | |
#define TMR_POST_1_4 3 | |
#define TMR_POST_1_5 4 | |
#define TMR_POST_1_6 5 | |
#define TMR_POST_1_7 6 | |
#define TMR_POST_1_8 7 | |
#define TMR_POST_1_9 8 | |
#define TMR_POST_1_10 9 | |
#define TMR_POST_1_11 10 | |
#define TMR_POST_1_12 11 | |
#define TMR_POST_1_13 12 | |
#define TMR_POST_1_14 13 | |
#define TMR_POST_1_15 14 | |
#define TMR_POST_1_16 15 | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment