rcc_periph_clock_enable(RCC_GPIOB);
rcc_periph_clock_enable(RCC_GPIOC);
rcc_periph_clock_enable(RCC_USART1);
+ rcc_periph_clock_enable(RCC_USART3);
rcc_periph_clock_enable(RCC_USB);
rcc_periph_reset_pulse(RST_GPIOA);
rcc_periph_reset_pulse(RST_GPIOB);
rcc_periph_reset_pulse(RST_GPIOC);
rcc_periph_reset_pulse(RST_USART1);
+ rcc_periph_reset_pulse(RST_USART3);
rcc_periph_reset_pulse(RST_USB);
}
static void tick_init(void)
{
- systick_set_frequency(1000, 72000000);
+ systick_set_frequency(1000, CPU_CLOCK_MHZ * 1000000);
systick_counter_enable();
systick_interrupt_enable();
}
/*** BSB ***/
#define BSB_MAX_SIZE 32
-#define BSB_RX_TIMEOUT 2 // 1-2 ms => 2-4 byte periods of silence
+#define BSB_RX_TIMEOUT 10 // ms
+
+#define DEBUG_BSB
+#ifdef DEBUG_BSB
+#define BSB_DEBUG(x...) debug_printf(x)
+#else
+#define BSB_DEBUG(x...) do { } while (0)
+#endif
static byte bsb_rx_buf[BSB_MAX_SIZE];
static byte bsb_rx_len;
+static u16 bsb_rx_crc;
static volatile u32 bsb_rx_timestamp;
// Passing received frames to the main loop
static byte bsb_rx_frame[BSB_MAX_SIZE];
static volatile byte bsb_rx_frame_len;
+static byte bsb_rx_frame_led;
struct bsb_stat {
u32 rx_noise;
u32 rx_invalid;
u32 rx_overruns;
u32 rx_timeouts;
+ u32 rx_bad_crc;
+ u32 rx_ok;
};
static struct bsb_stat bsb_stat;
+static u16 bsb_crc_update(u16 crc, byte data)
+{
+ crc = crc ^ (data << 8);
+ for (uint i=0; i<8; i++) {
+ if (crc & 0x8000)
+ crc = (crc << 1) ^ 0x1021;
+ else
+ crc <<= 1;
+ }
+ return crc;
+}
+
void usart3_isr(void)
{
u32 status = USART_SR(USART3);
if (status & USART_SR_RXNE) {
- uint ch = usart_recv(USART3);
+ uint ch = ~usart_recv(USART3) & 0xff;
bsb_rx_timestamp = ms_ticks;
+ BSB_DEBUG(" %02x", ch);
if (status & (USART_SR_FE | USART_SR_ORE | USART_SR_NE)) {
bsb_stat.rx_errors++;
bsb_rx_len = 0;
- } else if (!bsb_rx_len && ch != 0xdc) {
- // Waiting for start of frame
- bsb_stat.rx_noise++;
+ } else if (!bsb_rx_len) {
+ // Start of frame
+ if (ch == 0xdc) {
+ bsb_rx_buf[bsb_rx_len++] = ch;
+ bsb_rx_crc = bsb_crc_update(0, ch);
+ BSB_DEBUG("<");
+ } else {
+ bsb_stat.rx_noise++;
+ BSB_DEBUG("?");
+ }
} else {
bsb_rx_buf[bsb_rx_len++] = ch;
+ bsb_rx_crc = bsb_crc_update(bsb_rx_crc, ch);
if (bsb_rx_len < 4) {
// First three bytes: SOF, source addr, destination addr
} else if (bsb_rx_len == 4) {
if (bsb_rx_buf[3] < 7 || bsb_rx_buf[3] > BSB_MAX_SIZE) {
bsb_stat.rx_invalid++;
bsb_rx_len = 0;
+ BSB_DEBUG("!L");
}
} else if (bsb_rx_len == bsb_rx_buf[3]) {
- // Received a complete frame: pass it to the main loop
- if (bsb_rx_frame_len) {
- // The previous one was not sent yet
- bsb_stat.rx_overruns++;
+ // Received a complete frame: check CRC and pass it to the main loop
+ if (bsb_rx_crc) {
+ bsb_stat.rx_bad_crc++;
+ BSB_DEBUG("!C");
} else {
- memcpy(bsb_rx_frame, bsb_rx_buf, bsb_rx_buf[3]);
- barrier();
- bsb_rx_frame_len = bsb_rx_buf[3];
+ if (bsb_rx_frame_len) {
+ // The previous one was not sent yet
+ bsb_stat.rx_overruns++;
+ BSB_DEBUG("!O");
+ } else {
+ memcpy(bsb_rx_frame, bsb_rx_buf, bsb_rx_buf[3]);
+ bsb_rx_frame_len = bsb_rx_buf[3];
+ bsb_stat.rx_ok++;
+ BSB_DEBUG(".");
+ }
+ gpio_clear(GPIOB, GPIO1);
+ bsb_rx_frame_led = 100;
}
+ bsb_rx_len = 0;
}
}
}
usart_set_baudrate(USART3, 4800);
usart_set_databits(USART3, 9);
usart_set_stopbits(USART3, USART_STOPBITS_1);
- usart_set_mode(USART3, USART_MODE_TX_RX);
+ usart_set_mode(USART3, USART_MODE_RX);
usart_set_parity(USART3, USART_PARITY_ODD);
usart_set_flow_control(USART3, USART_FLOWCONTROL_NONE);
return USBD_REQ_NOTSUPP;
// We support reading of statistics via control requests
- debug_printf("USB: Control request: Read statistics\n");
+ debug_printf("USB: Reading statistics\n");
uint n = MIN(*len, sizeof(bsb_stat));
memcpy(*buf, (char *) &bsb_stat, n);
*len = n;
// Packet timeouts
cm_disable_interrupts();
barrier();
- if (bsb_rx_len && (bsb_rx_timestamp - ms_ticks) >= BSB_RX_TIMEOUT) {
+ if (bsb_rx_len && ms_ticks - bsb_rx_timestamp >= BSB_RX_TIMEOUT) {
bsb_rx_len = 0;
bsb_stat.rx_timeouts++;
+ BSB_DEBUG("!T");
+ }
+ if (bsb_rx_frame_led) {
+ if (!--bsb_rx_frame_led)
+ gpio_set(GPIOB, GPIO1);
}
cm_enable_interrupts();