#include #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; } } }