123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235 |
- #include "board.h"
- #include <avr/interrupt.h>
- #include <avr/io.h>
- #include <avr/sleep.h>
- #include <avr/wdt.h>
- #include <string.h>
- #include <util/delay.h>
- #define LED PB5
- void Board::toggle_led() { PORTB ^= (1 << LED); }
- void Board::init_start() {
- // Initialize the application including WDT, PORTB.5
- // We will now disable the watchdog.
- // Service the watchdog just to be sure to avoid pending timeout.
- wdt_reset();
- // Clear WDRF in MCUSR.
- MCUSR &= ~(1U << WDRF);
- // Write logical one to WDCE and WDE.
- // Keep the old prescaler setting to prevent unintentional time-out.
- WDTCSR |= (1U << WDCE) | (1U << WDE);
- // Turn off the WDT.
- WDTCSR = 0x00;
- // We will now initialize PORTB.5 to be used as an LED driver port.
- // Set PORTB.5 value to low.
- PORTB &= ~(1U << PORTB5);
- /* initializing PB5 which is connected to port 13 of uno as output*/
- DDRB |= (1 << LED);
- }
- void Board::enable_timer() {
- // We will now initialize the TIMER0 clock and interrupt.
- // Clear the TIMER0 overflow flag.
- TIFR0 = static_cast<std::uint8_t>(1U << TOV0);
- // Enable the TIMER0 overflow interrupt.
- TIMSK0 = static_cast<std::uint8_t>(1U << TOIE0);
- // Set the TIMER0 clock source to f_osc/8 = 2MHz and begin counting.
- TCCR0B = static_cast<std::uint8_t>(1U << CS01);
- }
- void Board::disable_timer() {
- // erase TIMER0 clock source;
- TCCR0B = 0;
- // Clear the TIMER0 overflow flag.
- TIMSK0 = 0;
- // Enable the TIMER0 overflow interrupt.
- TIMSK0 = 0;
- }
- std::uint64_t gpt_system_tick = 0;
- rl::TimePoint Board::get_now() {
- // The entire system-tick is composed of the static
- // 64-bit variable mcal_gpt_system_tick and the 8-bit
- // timer register TCNT0. These are concatenated together
- // in software as a cohesive, consistent 64-bit tick.
- // This subroutine returns the concatenated 64-bit
- // mcal_gpt_system_tick/TCNT0 64-bit system tick.
- // A multiple read of the tick is used in order
- // to ensure data consistency.
- // Do the first read of the TIMER0 counter and the system tick.
- const auto tim0_cnt_1 = TCNT0;
- const auto sys_tick_1 = gpt_system_tick;
- // Do the second read of the TIMER0 counter.
- const auto tim0_cnt_2 = TCNT0;
- // Perform the consistency check to obtain the concatenated,
- // consistent, 64-bit system-tick.
- const auto consistent_microsecond_tick =
- ((tim0_cnt_2 >= tim0_cnt_1)
- ? static_cast<std::uint64_t>(
- sys_tick_1 | static_cast<std::uint8_t>(tim0_cnt_1 >> 1U))
- : static_cast<std::uint64_t>(
- gpt_system_tick |
- static_cast<std::uint8_t>(tim0_cnt_2 >> 1U)));
- return consistent_microsecond_tick;
- }
- void adjust_timer(const rotor_light::Duration &value) {
- gpt_system_tick += value;
- }
- static UARTRxCallback uart_rx;
- static UARTTxCallback uart_tx;
- void Board::enable_uart(UARTRxCallback rx, UARTTxCallback tx) {
- uart_rx = rx;
- uart_tx = tx;
- // USART
- #define BAUD 9600
- #include <util/setbaud.h>
- UBRR0H = UBRRH_VALUE;
- UBRR0L = UBRRL_VALUE;
- UCSR0B = (1 << RXEN0) // enable rx
- | (1 << TXEN0) // enable tx
- | (1 << RXCIE0) // enable rx interrupt
- ;
- /* Set frame format: 8data, 2stop bit */
- UCSR0C = (1 << USBS0) | (3 << UCSZ00);
- }
- void Board::send_uart(char value) {
- // enable empty data buffer interrupt
- UCSR0B |= (1 << UDRIE0);
- while (!(UCSR0A & (1 << UDRE0))) {
- // NO-OP
- }
- UDR0 = value;
- }
- void Board::enable_usart() {
- // USART
- #define BAUD 9600
- #include <util/setbaud.h>
- UBRR0H = UBRRH_VALUE;
- UBRR0L = UBRRL_VALUE;
- UCSR0B = (1 << RXEN0) | (1 << TXEN0);
- /* Set frame format: 8data, 2stop bit */
- UCSR0C = (1 << USBS0) | (3 << UCSZ00);
- }
- void Board::send_usart(const char *data) { send_usart(data, strlen(data)); }
- void Board::send_usart(const char *data, size_t count) {
- auto end = data + count;
- while (data != end) {
- while (!(UCSR0A & (1 << UDRE0)))
- ;
- UDR0 = static_cast<uint8_t>(*data++);
- }
- }
- void Board::sleep(const rl::TimePoint &until) {
- auto now = get_now();
- auto left = until - now;
- auto amount = rl::Duration{};
- auto sleep_constant = uint8_t{};
- cli();
- disable_timer();
- while (left > 0) {
- cli();
- if (left < 15) {
- break;
- } else if (left < 30) {
- amount = 15;
- sleep_constant = WDTO_15MS;
- } else if (left < 60) {
- amount = 30;
- sleep_constant = WDTO_30MS;
- } else if (left < 120) {
- amount = 60;
- sleep_constant = WDTO_60MS;
- } else if (left < 250) {
- amount = 120;
- sleep_constant = WDTO_120MS;
- } else if (left < 500) {
- amount = 250;
- sleep_constant = WDTO_250MS;
- } else if (left < 1000) {
- amount = 500;
- sleep_constant = WDTO_500MS;
- } else if (left < 2000) {
- amount = 1000;
- sleep_constant = WDTO_1S;
- } else if (left < 4000) {
- amount = 2000;
- sleep_constant = WDTO_2S;
- } else if (left < 8000) {
- amount = 4000;
- sleep_constant = WDTO_4S;
- } else {
- amount = 8000;
- sleep_constant = WDTO_8S;
- }
- TCNT0 = 0;
- adjust_timer(amount * 1000);
- wdt_reset();
- wdt_enable(sleep_constant);
- // enable watchdog interrupt
- WDTCSR |= (1 << WDIE);
- set_sleep_mode(SLEEP_MODE_PWR_DOWN);
- sleep_enable();
- sei();
- sleep_cpu();
- sleep_disable();
- sei();
- left -= amount;
- }
- enable_timer();
- sei();
- }
- void Board::delay() { _delay_ms(1000); }
- ISR(TIMER0_OVF_vect) {
- // Increment the 64-bit system tick with 0x80, representing 128 microseconds.
- gpt_system_tick += UINT8_C(0x80);
- }
- ISR(USART_RX_vect) {
- if (UCSR0A & (1 << RXC0)) {
- uart_rx(static_cast<char>(UDR0));
- }
- }
- ISR(USART_UDRE_vect) {
- // disable empty data buffer interrupt
- UCSR0B &= ~(1 << UDRIE0);
- uart_tx();
- }
- ISR(WDT_vect) {
- // WDIE & WDIF is cleared in hardware upon entering this ISR
- wdt_disable();
- }
|