157 lines
3.8 KiB
C
157 lines
3.8 KiB
C
#include <stdio.h>
|
|
|
|
#include "ch32v003fun.h"
|
|
#include "simple_eeprom.h"
|
|
#include "state_manager.h"
|
|
|
|
#define RS485_DIR (1 << 0) // RS485 direction control
|
|
#define SRCLR (1 << 1) // Shift register clear (active low)
|
|
#define SRCLK (1 << 2) // Shift register clock
|
|
#define RCLK (1 << 3) // Storage register clock
|
|
#define SER (1 << 4) // Serial data input
|
|
|
|
// "protocol" defines
|
|
#define BOARD_ADDRESS 0x01
|
|
#define CMD_SET_OUTPUTS 0x01
|
|
#define BROADCAST_ADDR 0xFF
|
|
|
|
// "protocol" states
|
|
enum rx_states {
|
|
STATE_ADDR,
|
|
STATE_IGNORE,
|
|
STATE_CMD,
|
|
STATE_DATA_HIGH,
|
|
STATE_DATA_LOW
|
|
};
|
|
|
|
void setup_uart(int uartBRR) {
|
|
RCC->APB2PCENR |= RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOC |
|
|
RCC_APB2Periph_USART1 | RCC_APB2Periph_AFIO;
|
|
|
|
// RS485_DIR as output, set recv mode
|
|
GPIOC->CFGLR &= ~(0xf << (4 * 0));
|
|
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * 0);
|
|
GPIOC->BCR = RS485_DIR;
|
|
|
|
// UART pins (PD5=TX, PD6=RX)
|
|
GPIOD->CFGLR &= ~(0xf << (4 * 5) | 0xf << (4 * 6));
|
|
GPIOD->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 5);
|
|
GPIOD->CFGLR |= GPIO_CNF_IN_FLOATING << (4 * 6);
|
|
|
|
// 115200 8N1
|
|
USART1->CTLR1 =
|
|
USART_WordLength_8b | USART_Parity_No | USART_Mode_Tx | USART_Mode_Rx;
|
|
USART1->CTLR2 = USART_StopBits_1;
|
|
USART1->CTLR3 = USART_HardwareFlowControl_None;
|
|
USART1->BRR = uartBRR;
|
|
USART1->CTLR1 |= CTLR1_UE_Set;
|
|
}
|
|
|
|
void setup_gpio(void) {
|
|
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC;
|
|
|
|
// PC1-PC4 as out
|
|
for (int pin = 1; pin <= 4; pin++) {
|
|
GPIOC->CFGLR &= ~(0xf << (4 * pin));
|
|
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * pin);
|
|
}
|
|
|
|
GPIOC->BCR = SRCLR | SRCLK | RCLK | SER;
|
|
}
|
|
|
|
void shift_out(uint16_t data) {
|
|
GPIOC->BCR = RCLK;
|
|
|
|
// reorder
|
|
uint16_t ordered_data = ((data & 0xFF00) >> 8) | // 1st reg (Q0-Q7)
|
|
((data & 0x00FF) << 8); // 2nd reg (Q8-Q15)
|
|
|
|
// shift out 16 bits, MSB 1st
|
|
for (int8_t i = 15; i >= 0; i--) {
|
|
GPIOC->BCR = SRCLK;
|
|
if (ordered_data & (1 << i)) {
|
|
GPIOC->BSHR = SER;
|
|
} else {
|
|
GPIOC->BCR = SER;
|
|
}
|
|
GPIOC->BSHR = SRCLK;
|
|
}
|
|
|
|
// latch
|
|
GPIOC->BSHR = RCLK;
|
|
GPIOC->BCR = RCLK;
|
|
}
|
|
|
|
uint8_t uart_receive_byte(void) {
|
|
while (!(USART1->STATR & USART_FLAG_RXNE));
|
|
return USART1->DATAR & 0xFF;
|
|
}
|
|
|
|
int main(void) {
|
|
SystemInit();
|
|
setup_gpio();
|
|
setup_uart(UART_BRR);
|
|
|
|
// reset shift reg
|
|
GPIOC->BSHR = SRCLR;
|
|
GPIOC->BSHR = RCLK; // rising edge on RCLK
|
|
GPIOC->BCR = RCLK;
|
|
|
|
// load last state
|
|
uint16_t current_state = load_state();
|
|
printf("Loaded state: %04x\n", current_state);
|
|
shift_out(current_state);
|
|
|
|
uint8_t rx_state = STATE_ADDR;
|
|
uint8_t addr, cmd;
|
|
uint16_t data = 0;
|
|
uint8_t bytes_to_ignore = 0;
|
|
|
|
printf("SystemClk:%d\r\n", FUNCONF_SYSTEM_CORE_CLOCK);
|
|
printf("ChipID:%08lx\r\n", *(uint32_t *)0x1FFFF7C4);
|
|
|
|
while (1) {
|
|
uint8_t byte = uart_receive_byte();
|
|
|
|
switch (rx_state) {
|
|
case STATE_ADDR:
|
|
addr = byte;
|
|
if (addr == BOARD_ADDRESS || addr == BROADCAST_ADDR) {
|
|
rx_state = STATE_CMD;
|
|
} else {
|
|
// crc??))
|
|
bytes_to_ignore = 3; // skip cmd + data_high + data_low
|
|
rx_state = STATE_IGNORE;
|
|
}
|
|
break;
|
|
|
|
case STATE_IGNORE:
|
|
bytes_to_ignore--;
|
|
if (bytes_to_ignore == 0) {
|
|
rx_state = STATE_ADDR;
|
|
}
|
|
break;
|
|
|
|
case STATE_CMD:
|
|
cmd = byte;
|
|
rx_state = STATE_DATA_HIGH;
|
|
break;
|
|
|
|
case STATE_DATA_HIGH:
|
|
data = (uint16_t)byte << 8;
|
|
rx_state = STATE_DATA_LOW;
|
|
break;
|
|
|
|
case STATE_DATA_LOW:
|
|
data |= byte;
|
|
if (cmd == CMD_SET_OUTPUTS) {
|
|
printf("Set outputs: 0x%04X\n", data);
|
|
shift_out(data);
|
|
save_state(data);
|
|
dump_eeprom();
|
|
}
|
|
rx_state = STATE_ADDR;
|
|
break;
|
|
}
|
|
}
|
|
} |