164 lines
3.7 KiB
C
164 lines
3.7 KiB
C
//
|
|
// Created by vlad on 17.08.22.
|
|
//
|
|
#include "platform.h"
|
|
#include "config.h"
|
|
#include <avr/io.h>
|
|
#include <avr/interrupt.h>
|
|
|
|
static char systick_flag;
|
|
uint16_t sensor_1;
|
|
uint16_t sensor_2;
|
|
|
|
ISR(TIMER1_OVF_vect) {
|
|
systick_flag = 1;
|
|
// LED2_Toggle();
|
|
}
|
|
|
|
void platform_init() {
|
|
// инициализация GPIO
|
|
DDRD = INIT_DDRD;
|
|
DDRB = INIT_DDRB;
|
|
|
|
DIDR = 0x03; // отключение цифрового ввода/вывода на входах компаратора
|
|
|
|
// инициализация юарта
|
|
uart_init();
|
|
|
|
// инициализация таймера 1 (16-ти битный)
|
|
|
|
systick_flag = 0;
|
|
|
|
// mode=14 (FastPWM, top in ICR1), x64, ICR1=1000000/64=15625
|
|
TCCR1B = (1 << WGM13) | (1 << WGM12);
|
|
TCCR1A = (1 << WGM11);
|
|
|
|
// выставляем TOP
|
|
ICR1 = (uint16_t)(F_CPU / 64);
|
|
|
|
// разрешаем прерывание по переполнению
|
|
TIMSK |= (1 << TOV1);
|
|
|
|
TCCR1B |= (1 << CS11) | (1 << CS10); // выставляем x64, то есть запускаем таймер
|
|
|
|
sei();
|
|
}
|
|
|
|
void platform_wait_for_interrupt() {
|
|
// для режима сна Idle нужно отрубить компаратор (в даташите просили)
|
|
// в других режимах сна он отрубается автоматически
|
|
char acsr = ACSR;
|
|
ACSR |= (1 << ACD); // чтобы отрубить компаратор нужно записать 1 в этот бит
|
|
|
|
MCUCR |= (1 << SE);
|
|
asm volatile ("sleep");
|
|
MCUCR &= ~(1 << SE);
|
|
|
|
// восстанавливаем состояние компаратора
|
|
ACSR |= acsr;
|
|
}
|
|
|
|
void systick_sync() {
|
|
systick_flag = 0; // можно не запрещать прерывания: операция атомарна
|
|
for(;;) {
|
|
cli();
|
|
char flag = systick_flag;
|
|
if (flag) {
|
|
systick_flag = 0;
|
|
}
|
|
// else {
|
|
// platform_wait_for_interrupt();
|
|
// }
|
|
sei();
|
|
if (flag) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void uart_init() {
|
|
// U2X=1, baud=9600, error=0.2%, f=1M
|
|
UBRRH = 0;
|
|
UBRRL = 12;
|
|
|
|
UCSRA = (1 << U2X);
|
|
UCSRB = (1 << TXEN) | (1 << RXEN);
|
|
}
|
|
|
|
void uart_deinit() {
|
|
UCSRB = 0; // снимаем RXEN и TXEN
|
|
}
|
|
|
|
void uart_write_char(char c) {
|
|
while ((UCSRA & (1 << UDRE)) == 0)
|
|
;
|
|
UDR = c;
|
|
}
|
|
|
|
void uart_write_str(const char* str) {
|
|
while (1) {
|
|
char c = *(str++);
|
|
if (c == '\0') {
|
|
break;
|
|
}
|
|
uart_write_char(c);
|
|
}
|
|
}
|
|
|
|
void uart_write_fstr(PGM_P str) {
|
|
while (1) {
|
|
char c = pgm_read_byte(str++);
|
|
if (c == '\0') {
|
|
break;
|
|
}
|
|
uart_write_char(c);
|
|
}
|
|
}
|
|
|
|
char uart_read_char() {
|
|
while (!(UCSRA & (1 << RXC)))
|
|
;
|
|
return UDR;
|
|
}
|
|
|
|
void uart_discard_input() {
|
|
while (UCSRA & (1 << RXC)) {
|
|
char __attribute__((__unused__)) _tmp = UDR;
|
|
}
|
|
}
|
|
|
|
void platform_read_sensors() {
|
|
EXTPWR_EN_Set();
|
|
systick_sync();
|
|
sensor_1 = 0;
|
|
sensor_2 = 0;
|
|
uint8_t states = FRQ_Gpio & (FRQ1_Pin | FRQ2_Pin);
|
|
|
|
for(;;) {
|
|
uint8_t tmp = FRQ_Gpio;
|
|
|
|
if ((tmp & FRQ1_Pin) != (states & FRQ1_Pin)) {
|
|
states = (states & (~FRQ1_Pin)) | tmp;
|
|
sensor_1++;
|
|
}
|
|
|
|
if ((tmp & FRQ2_Pin) != (states & FRQ2_Pin)) {
|
|
states = (states & (~FRQ2_Pin)) | tmp;
|
|
sensor_2++;
|
|
}
|
|
|
|
cli();
|
|
char flag = systick_flag;
|
|
if (flag) {
|
|
systick_flag = 0;
|
|
}
|
|
sei();
|
|
if (flag) {
|
|
break;
|
|
}
|
|
}
|
|
EXTPWR_EN_Reset();
|
|
// быстрое деление на 2 (считалось каждое изменение)
|
|
sensor_2 >>= 1;
|
|
sensor_1 >>= 1;
|
|
} |