From 259ee0e7022ce15f4f2c8294a4fc3de7005d7fab Mon Sep 17 00:00:00 2001 From: fishsoupisgood Date: Mon, 29 Apr 2019 07:30:28 +0100 Subject: working with one set of stripes --- app/Makefile | 56 +++++++++++ app/cdcacm.c | 285 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ app/dfu.c | 80 ++++++++++++++++ app/main.c | 34 +++++++ app/project.h | 30 ++++++ app/prototypes.h | 35 +++++++ app/ring.c | 64 +++++++++++++ app/ring.h | 7 ++ app/ticker.c | 60 ++++++++++++ app/timex.c | 248 +++++++++++++++++++++++++++++++++++++++++++++++ app/timex.ld | 43 +++++++++ app/usart.c | 87 +++++++++++++++++ 12 files changed, 1029 insertions(+) create mode 100644 app/Makefile create mode 100644 app/cdcacm.c create mode 100644 app/dfu.c create mode 100644 app/main.c create mode 100644 app/project.h create mode 100644 app/prototypes.h create mode 100644 app/ring.c create mode 100644 app/ring.h create mode 100644 app/ticker.c create mode 100644 app/timex.c create mode 100644 app/timex.ld create mode 100644 app/usart.c (limited to 'app') diff --git a/app/Makefile b/app/Makefile new file mode 100644 index 0000000..6168bfe --- /dev/null +++ b/app/Makefile @@ -0,0 +1,56 @@ +## +## This file is part of the libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## +## This library is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This library is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this library. If not, see . +## + +CPROTO=cproto +PROG=timex + + +V=1 +default: ${PROG}.elf + +CSRCS= main.c cdcacm.c dfu.c ring.c usart.c ticker.c timex.c +HSRCS = project.h + + +BINARY = ${PROG} +OBJS = ${CSRCS:%.c=%.o} + +include ../Makefile.include + +DID=$(shell printf '\#include "id.h"\nID_PRODUCT' | ${CC} -I.. -E - | grep -v ^\# ) +VID=$(shell printf '\#include "id.h"\nID_VENDOR' | ${CC} -I.. -E - | grep -v ^\# ) + +INCLUDES += -I.. + +dfu:${PROG}.dfu + dfu-util -R -a 0 -d ${VID}:${DID} -s 0x08002000:leave -D $< + +program: ${PROG}.elf + echo halt | nc -t localhost 4444 + echo flash write_image erase ${PWD}/$< 0x2000 | nc -t localhost 4444 + echo reset run | nc -t localhost 4444 + +protos: + echo -n > prototypes.h + ${CPROTO} $(INCLUDES) $(DEFINES) -e -v ${CSRCS} > prototypes.h.tmp + mv -f prototypes.h.tmp prototypes.h + + +tidy: + astyle -A3 -s2 --attach-extern-c -L -c -w -Y -m0 -f -p -H -U -k3 -xj -xd ${CSRCS} ${HSRCS} || astyle -A3 -s2 -L -c -w -Y -m0 -f -p -H -U -k3 -xj -xd ${CSRCS} ${HSRCS} diff --git a/app/cdcacm.c b/app/cdcacm.c new file mode 100644 index 0000000..f437a10 --- /dev/null +++ b/app/cdcacm.c @@ -0,0 +1,285 @@ +#include "project.h" + + +#define BUFFER_SIZE 512 + +ring_t cdcacm_rx_ring; +static uint8_t cdcacm_rx_ring_buf[BUFFER_SIZE]; + +ring_t cdcacm_tx_ring; +static uint8_t cdcacm_tx_ring_buf[BUFFER_SIZE]; + + +static const struct usb_device_descriptor dev = { + .bLength = USB_DT_DEVICE_SIZE, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = USB_CLASS_CDC, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = 64, + .idVendor = ID_VENDOR, + .idProduct = ID_PRODUCT, + .bcdDevice = 0x0200, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 3, + .bNumConfigurations = 1, +}; + + +static const struct usb_endpoint_descriptor comm_endp[] = { + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x83, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 16, + .bInterval = 255, + } +}; + +static const struct usb_endpoint_descriptor data_endp[] = { + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x01, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = 64, + .bInterval = 1, + }, + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x82, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = 64, + .bInterval = 1, + } +}; + +static const struct { + struct usb_cdc_header_descriptor header; + struct usb_cdc_call_management_descriptor call_mgmt; + struct usb_cdc_acm_descriptor acm; + struct usb_cdc_union_descriptor cdc_union; +} __attribute__ ((packed)) cdcacm_functional_descriptors = { + .header = { + .bFunctionLength = sizeof (struct usb_cdc_header_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_HEADER, + .bcdCDC = 0x0110, + }, + .call_mgmt = { + .bFunctionLength = + sizeof (struct usb_cdc_call_management_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT, + .bmCapabilities = 0, + .bDataInterface = 1, + }, + .acm = { + .bFunctionLength = sizeof (struct usb_cdc_acm_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_ACM, + .bmCapabilities = 0, + }, + .cdc_union = { + .bFunctionLength = sizeof (struct usb_cdc_union_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_UNION, + .bControlInterface = 0, + .bSubordinateInterface0 = 1, + } +}; + +static const struct usb_interface_descriptor comm_iface = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_CDC, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, + .bInterfaceProtocol = USB_CDC_PROTOCOL_AT, + .iInterface = 0, + .endpoint = comm_endp, + .extra = &cdcacm_functional_descriptors, + .extralen = sizeof (cdcacm_functional_descriptors) +}; + +static const struct usb_interface_descriptor data_iface = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 1, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_DATA, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = 0, + .endpoint = data_endp, +}; + +static const struct usb_interface ifaces[] = { + { + .num_altsetting = 1, + .altsetting = &comm_iface, + }, + { + .num_altsetting = 1, + .altsetting = &data_iface, + }, +#ifdef INCLUDE_DFU_INTERFACE + { + .num_altsetting = 1, + .altsetting = &dfu_iface, + }, +#endif +}; + +static const struct usb_config_descriptor config = { + .bLength = USB_DT_CONFIGURATION_SIZE, + .bDescriptorType = USB_DT_CONFIGURATION, + .wTotalLength = 0, +#ifdef INCLUDE_DFU_INTERFACE + .bNumInterfaces = 3, +#else + .bNumInterfaces = 2, +#endif + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = 0x80, + .bMaxPower = 0x32, + .interface = ifaces, +}; + +static const char *usb_strings[] = { + "Meh", + "Fish", + "Soup", +#ifdef INCLUDE_DFU_INTERFACE + "DFU", +#endif +}; + +/* Buffer to be used for control requests. */ +uint8_t usbd_control_buffer[128]; + +usbd_device *usbd_dev; + + + +static int cdcacm_control_request (usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, + uint16_t *len, + usbd_control_complete_callback *complete) +{ + (void) complete; + (void) buf; + (void) usbd_dev; +#ifdef INCLUDE_DFU_INTERFACE + + if (dfu_control_request (usbd_dev, req, buf, len, complete)) + return 1; + +#endif + + switch (req->bRequest) { + case USB_CDC_REQ_SET_CONTROL_LINE_STATE: { + /* + * This Linux cdc_acm driver requires this to be implemented + * even though it's optional in the CDC spec, and we don't + * advertise it in the ACM functional descriptor. + */ + char local_buf[10]; + struct usb_cdc_notification *notif = (void *) local_buf; + /* We echo signals back to host as notification. */ + notif->bmRequestType = 0xA1; + notif->bNotification = USB_CDC_NOTIFY_SERIAL_STATE; + notif->wValue = 0; + notif->wIndex = 0; + notif->wLength = 2; + local_buf[8] = req->wValue & 3; + local_buf[9] = 0; + // usbd_ep_write_packet(0x83, buf, 10); + return 1; + } + + case USB_CDC_REQ_SET_LINE_CODING: + + if (*len < sizeof (struct usb_cdc_line_coding)) + return 0; + + return 1; + } + + return 0; +} + + +void cdcacm_tick (void) +{ + unsigned ep = 0x82; + uint8_t buf[16]; + uint8_t *ptr = buf; + size_t n = 0; + + if (ring_empty (&cdcacm_tx_ring)) + return; + + if ((*USB_EP_REG (ep & 0x7f) & USB_EP_TX_STAT) == USB_EP_TX_STAT_VALID) + return; + + while ((!ring_read_byte (&cdcacm_tx_ring, ptr++)) && (n < sizeof (buf))) + n++; + + usbd_ep_write_packet (usbd_dev, ep, buf, n); +} + + +static void cdcacm_data_rx_cb (usbd_device *usbd_dev, uint8_t ep) +{ + (void) ep; + uint8_t buf[64]; + int len = usbd_ep_read_packet (usbd_dev, 0x01, buf, 64); + + if (len) { + ring_write (&cdcacm_rx_ring, buf, len); + ring_write (&timex_ring, buf, len); + } +} + +static void cdcacm_set_config (usbd_device *usbd_dev, uint16_t wValue) +{ + (void) wValue; + usbd_ep_setup (usbd_dev, 0x01, USB_ENDPOINT_ATTR_BULK, 64, cdcacm_data_rx_cb); + usbd_ep_setup (usbd_dev, 0x82, USB_ENDPOINT_ATTR_BULK, 64, NULL); + usbd_ep_setup (usbd_dev, 0x83, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL); + usbd_register_control_callback (usbd_dev, + USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, + USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, + cdcacm_control_request); +} + +void usb_init (void) +{ + ring_init (&cdcacm_rx_ring, cdcacm_rx_ring_buf, sizeof (cdcacm_rx_ring_buf)); + ring_init (&cdcacm_tx_ring, cdcacm_tx_ring_buf, sizeof (cdcacm_tx_ring_buf)); + usbd_dev = usbd_init (&stm32f103_usb_driver, + &dev, + &config, + usb_strings, +#ifdef INCLUDE_DFU_INTERFACE + 4, +#else + 3, +#endif + usbd_control_buffer, + sizeof (usbd_control_buffer)); + usbd_register_set_config_callback (usbd_dev, cdcacm_set_config); +} + + + diff --git a/app/dfu.c b/app/dfu.c new file mode 100644 index 0000000..d79b474 --- /dev/null +++ b/app/dfu.c @@ -0,0 +1,80 @@ +#include "project.h" + +#ifdef INCLUDE_DFU_INTERFACE + +extern uint32_t dfu_flag; + +const struct usb_dfu_descriptor dfu_function = { + .bLength = sizeof (struct usb_dfu_descriptor), + .bDescriptorType = DFU_FUNCTIONAL, + .bmAttributes = USB_DFU_CAN_DOWNLOAD, + .wDetachTimeout = 255, + .wTransferSize = 1024, + .bcdDFUVersion = 0x011A, +}; + +const struct usb_interface_descriptor dfu_iface = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 2, + .bAlternateSetting = 0, + .bNumEndpoints = 0, + .bInterfaceClass = 0xFE, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 1, + .iInterface = 4, + + .extra = &dfu_function, + .extralen = sizeof (dfu_function), +}; + + +static int +dfu_detach_complete (usbd_device *usbd_dev, struct usb_setup_data *req) +{ + (void) req; + (void) usbd_dev; + dfu_flag = 0xfee1dead; + scb_reset_core(); + return 1; +} + +int +dfu_control_request (usbd_device *usbd_dev, struct usb_setup_data *req, + uint8_t **buf, uint16_t *len, + usbd_control_complete_callback *complete) +{ + (void) buf; + (void) len; + (void) usbd_dev; + + if ((req->bmRequestType & 0x7F) != 0x21) { + return 0; /* Only accept class request. */ + } + + switch (req->bRequest) { + case DFU_GETSTATUS: { + (*buf) [0] = DFU_STATUS_OK; + (*buf) [1] = 0; + (*buf) [2] = 0; + (*buf) [3] = 0; + (*buf) [4] = STATE_APP_IDLE; + (*buf) [5] = 0; /* iString not used here */ + *len = 6; + return 1; + } + + case DFU_GETSTATE: + /* Return state with no state transision. */ + *buf[0] = STATE_APP_IDLE; + *len = 1; + return 1; + + case DFU_DETACH: + *complete = dfu_detach_complete; + return 1; + } + + return 0; +} +#endif diff --git a/app/main.c b/app/main.c new file mode 100644 index 0000000..06644bd --- /dev/null +++ b/app/main.c @@ -0,0 +1,34 @@ +#include "project.h" + + + + + +int main (void) +{ + /*set up pll */ + rcc_clock_setup_in_hse_8mhz_out_72mhz(); + /*turn on clocks to periferals */ + rcc_periph_clock_enable (RCC_GPIOA); + rcc_periph_clock_enable (RCC_GPIOB); + rcc_periph_clock_enable (RCC_GPIOC); + rcc_periph_clock_enable (RCC_USART1); + rcc_periph_clock_enable (RCC_AFIO); + nvic_set_priority (NVIC_SYSTICK_IRQ, 0x80); + nvic_set_priority (NVIC_USART1_IRQ, 0x40); + gpio_set_mode (LED_BANK, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, LED_GPIO); + + timex_init(); + ticker_init(); + usart_init(); + + usb_init(); + + printf ("Morning chaps!\r\n"); + + for (;;) + usbd_poll (usbd_dev); + + return 0; +} + diff --git a/app/project.h b/app/project.h new file mode 100644 index 0000000..5731f0d --- /dev/null +++ b/app/project.h @@ -0,0 +1,30 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define INCLUDE_DFU_INTERFACE + +#ifdef INCLUDE_DFU_INTERFACE +#include +#include +#endif + +#include +#include + +#define LED_GPIO GPIO13 +#define LED_BANK GPIOC + +#include "ring.h" + +#include "prototypes.h" diff --git a/app/prototypes.h b/app/prototypes.h new file mode 100644 index 0000000..f153902 --- /dev/null +++ b/app/prototypes.h @@ -0,0 +1,35 @@ +/* main.c */ +extern int main(void); +/* cdcacm.c */ +extern ring_t cdcacm_rx_ring; +extern ring_t cdcacm_tx_ring; +extern uint8_t usbd_control_buffer[128]; +extern usbd_device *usbd_dev; +extern void cdcacm_tick(void); +extern void usb_init(void); +/* dfu.c */ +extern const struct usb_dfu_descriptor dfu_function; +extern const struct usb_interface_descriptor dfu_iface; +extern int dfu_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, usbd_control_complete_callback *complete); +/* ring.c */ +extern void ring_init(ring_t *r, uint8_t *buf, size_t len); +extern int ring_write_byte(ring_t *r, uint8_t c); +extern int ring_empty(ring_t *r); +extern int ring_read_byte(ring_t *r, uint8_t *c); +extern int ring_write(ring_t *r, uint8_t *buf, size_t len); +/* usart.c */ +extern ring_t usart_rx_ring; +extern ring_t usart_tx_ring; +extern void usart1_isr(void); +extern void usart_kick(void); +extern int _write(int file, char *ptr, int len); +extern void usart_init(void); +/* ticker.c */ +extern unsigned led; +extern void delay_us(uint32_t d); +extern void sys_tick_handler(void); +extern void ticker_init(void); +/* timex.c */ +extern ring_t timex_ring; +extern void timex_tick(void); +extern void timex_init(void); diff --git a/app/ring.c b/app/ring.c new file mode 100644 index 0000000..26bba3a --- /dev/null +++ b/app/ring.c @@ -0,0 +1,64 @@ +#include "project.h" + + +static inline size_t +ring_next (ring_t *r, size_t p) +{ + p++; + + if (p >= r->size) + p -= r->size; + + return p; +} + +void +ring_init (ring_t *r, uint8_t *buf, size_t len) +{ + r->data = buf; + r->size = len; + r->write = 0; + r->read = 0; +} + +int +ring_write_byte (ring_t *r, uint8_t c) +{ + size_t n = ring_next (r, r->write); + + if (n == r->read) + return -1; + + r->data[r->write] = c; + r->write = n; + return 0; +} + +int ring_empty (ring_t *r) +{ + return (r->read == r->write); +} + +int +ring_read_byte (ring_t *r, uint8_t *c) +{ + size_t n = ring_next (r, r->read); + + if (r->read == r->write) + return -1; + + *c = r->data[r->read]; + r->read = n; + return 0; +} + +int +ring_write (ring_t *r, uint8_t *buf, size_t len) +{ + while (len--) { + if (ring_write_byte (r, * (buf++))) + return -1; + } + + return 0; +} diff --git a/app/ring.h b/app/ring.h new file mode 100644 index 0000000..ba8887b --- /dev/null +++ b/app/ring.h @@ -0,0 +1,7 @@ +typedef struct ring +{ + uint8_t *data; + size_t size; + size_t write; + size_t read; +} ring_t; diff --git a/app/ticker.c b/app/ticker.c new file mode 100644 index 0000000..ea832c8 --- /dev/null +++ b/app/ticker.c @@ -0,0 +1,60 @@ +#include "project.h" + + +static volatile uint32_t ticks; +static uint32_t scale = 30; + +unsigned led = 32000; + +void +delay_us (uint32_t d) +{ + d *= scale; + + while (d--) + __asm__ ("nop"); +} + +void +sys_tick_handler (void) +{ + timex_tick(); + cdcacm_tick(); + + ticks++; + + if (led) { + gpio_clear (LED_BANK, LED_GPIO); + led--; + } else + gpio_set (LED_BANK, LED_GPIO); + +} + + +void +ticker_init (void) +{ + uint32_t v, w; + /*Start periodic timer */ + systick_set_clocksource (STK_CSR_CLKSOURCE_AHB); + systick_set_reload (2288); + /* 72MHz / 2288 => 31.469531kHz (we wanted 31.46875) */ + systick_interrupt_enable(); + systick_counter_enable(); + + /*Calibrate the delay loop */ + do { + scale--; + v = ticks; + + while (v == ticks) + ; + + delay_us (32); + w = ticks; + v++; + w -= v; + } while (w); +} + diff --git a/app/timex.c b/app/timex.c new file mode 100644 index 0000000..40f43ad --- /dev/null +++ b/app/timex.c @@ -0,0 +1,248 @@ +#include "project.h" + +/* + * VGA 640x480 mode timings are + * + * 48 640 16 96 + * 10 480 33 2 + * + * at 25.175 Hz + * + */ + +/* + * Two bytes are shown per video frame one starting at + * scanline 70, the other at 255, and there are 15 + * scanlines between bits. + * + */ + +#define SL_BYTE_1_START 70 +#define SL_BIT 15 +#define SL_BYTE_2_START 255 + +#undef PAD +#undef EX + +#define SL_ON(byte,bit) ((SL_BYTE_ ## byte ## _START) + (SL_BIT * (bit))) +#define SL_OFF(byte,bit) (SL_ON(byte,bit) + 1) + + +#define SEND_BIT(byte,bit,data) \ + case SL_ON(byte,bit): \ + timex_led((data) & 1); \ + break; \ + case SL_OFF(byte,bit): \ + timex_led(1); \ + break + +#define SEND_BIT_SHIFT(byte,bit,data) \ + case SL_ON(byte,bit): \ + timex_led((data) & 1); \ + data>>=1; \ + break; \ + case SL_OFF(byte,bit): \ + timex_led(1); \ + break + +#define SEND_BYTE(byte, start, data) \ + SEND_BIT(byte,0,start); \ + SEND_BIT_SHIFT(byte,1,data); \ + SEND_BIT_SHIFT(byte,2,data); \ + SEND_BIT_SHIFT(byte,3,data); \ + SEND_BIT_SHIFT(byte,4,data); \ + SEND_BIT_SHIFT(byte,5,data); \ + SEND_BIT_SHIFT(byte,6,data); \ + SEND_BIT_SHIFT(byte,7,data); \ + SEND_BIT_SHIFT(byte,8,data) + + + +/* + * We ignore the horizontal front/back/sync and drive the system timer at + * the horizontal sync frequency of 31.46875kHz or as close as we can manage + */ + + +#define BUFFER_SIZE 512 + +#define TIMEX_BANK GPIOB +#define TIMEX_GPIO GPIO9 + +ring_t timex_ring; +static uint8_t timex_ring_buf[BUFFER_SIZE]; + + +static inline void timex_led (int v) +{ + if (v) + gpio_set (TIMEX_BANK, TIMEX_GPIO); + else + gpio_clear (TIMEX_BANK, TIMEX_GPIO); +} + + +#define SYNCS 200 +typedef enum { + STATE_MAGIC1, + STATE_MAGIC2, + STATE_MAGIC3, + STATE_MAGIC4, + STATE_IDLE, + STATE_SYNC1, + STATE_SYNC2, + STATE_PACKET_HEADER, + STATE_PACKET_DATA, + STATE_PACKET_PAD, + STATE_PACKET_RECOVERY, + +} Timex_state; + + + +static int get_data (uint8_t *start, uint8_t *data) +{ + static Timex_state state = STATE_MAGIC1; + static unsigned len; + static unsigned pad; + + + *start = 0; + + switch (state) { + case STATE_MAGIC1: + if (ring_empty (&timex_ring)) + return 1; + + case STATE_IDLE: + if (ring_empty (&timex_ring)) + return 1; + + state = STATE_SYNC1; + len = SYNCS; + break; + + case STATE_SYNC1: + *data = 0x55; + len--; + + if (!len) state = STATE_SYNC2; + + break; + + case STATE_SYNC2: + *data = 0xaa; + state = STATE_PACKET_HEADER; + break; + + case STATE_PACKET_HEADER: + if (ring_read_byte (&timex_ring, data)) { + /*No more data*/ + state = STATE_MAGIC1; + return 1; + } + len = *data -1 ; + state = STATE_PACKET_DATA; +#ifdef PAD + pad =(*data &1); +#else + pad=0; +#endif + break; + + case STATE_PACKET_DATA: + ring_read_byte (&timex_ring, data); + len--; + + if (!len) { +#ifdef PAD + len = 20; +#else + len = 10; +#endif + + if (pad) + state = STATE_PACKET_PAD; + else + state = STATE_PACKET_RECOVERY; + } + + break; + + case STATE_PACKET_PAD: + *data=0x00; + state = STATE_PACKET_RECOVERY; + break; + + + case STATE_PACKET_RECOVERY: + *start = 1; + *data = 0xff; + len--; + + if (!len) state = STATE_PACKET_HEADER; + + break; + } + + + return 0; +} + +void timex_tick (void) +{ + static unsigned line = 0; + static uint8_t data, start; + + + switch (line) { + case (SL_BYTE_1_START-2): + if (get_data (&start, &data)) { + line = 0; + return; + } + break; + + SEND_BYTE (1, start, data); + +#ifdef PAD + case (SL_BYTE_2_START-2): + if (get_data (&start, &data)) { + line = 0; + return; + } + break; + SEND_BYTE (2, start, data); +#endif + + + } + + + line++; + + if (line == 525) + line = 0; +} + +#ifdef EX +uint8_t ex[]={ +#include "/root/projects/timex_datalink/datalink-1.0.1/fish.h" +}; +#endif + + + + +void +timex_init (void) +{ + ring_init (&timex_ring, timex_ring_buf, sizeof (timex_ring_buf)); +#ifdef EX + ring_write(&timex_ring,ex,sizeof(ex)); +#endif + gpio_set_mode (TIMEX_BANK, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, TIMEX_GPIO); + + + timex_led (1); +} diff --git a/app/timex.ld b/app/timex.ld new file mode 100644 index 0000000..d30f63f --- /dev/null +++ b/app/timex.ld @@ -0,0 +1,43 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Linker script for Olimex STM32-H103 (STM32F103RBT6, 128K flash, 20K RAM). */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08002000, LENGTH = 60K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K +} + +/* Include the common ld script. */ +INCLUDE libopencm3_stm32f1.ld + +dfu_shared_location = ORIGIN(ram) + LENGTH(ram) - 1024; + +/* PROVIDE(_stack = dfu_shared_location ); */ + +SECTIONS +{ + .dfu_shared dfu_shared_location :{ + dfu_flag = .; + } +} + + diff --git a/app/usart.c b/app/usart.c new file mode 100644 index 0000000..4ba8da2 --- /dev/null +++ b/app/usart.c @@ -0,0 +1,87 @@ +#include "project.h" + +#define BUFFER_SIZE 512 + +ring_t usart_rx_ring; +static uint8_t usart_rx_ring_buf[BUFFER_SIZE]; + +ring_t usart_tx_ring; +static uint8_t usart_tx_ring_buf[BUFFER_SIZE]; + +void +usart1_isr (void) +{ + uint8_t data; + + /* Check if we were called because of RXNE. */ + if (((USART_CR1 (USART1) & USART_CR1_RXNEIE) != 0) && + ((USART_SR (USART1) & USART_SR_RXNE) != 0)) { + /* Retrieve the data from the peripheral. */ + data = usart_recv (USART1); + ring_write_byte (&usart_rx_ring, data); + } + + /* Check if we were called because of TXE. */ + if (((USART_CR1 (USART1) & USART_CR1_TXEIE) != 0) && + ((USART_SR (USART1) & USART_SR_TXE) != 0)) { + if (ring_read_byte (&usart_tx_ring, &data)) { + /*No more data, Disable the TXE interrupt, it's no longer needed. */ + USART_CR1 (USART1) &= ~USART_CR1_TXEIE; + } else + usart_send (USART1, data); + } +} + +void usart_kick (void) +{ + if (!ring_empty (&usart_tx_ring)) + USART_CR1 (USART1) |= USART_CR1_TXEIE; +} + + +int +_write (int file, char *ptr, int len) +{ + int ret; + + if (file == 1) { + ret = ring_write (&usart_tx_ring, (uint8_t *) ptr, len); + usart_kick(); + + if (ret < 0) + ret = -ret; + + return ret; + } + + errno = EIO; + return -1; +} + + + + +void +usart_init (void) +{ + ring_init (&usart_rx_ring, usart_rx_ring_buf, sizeof (usart_rx_ring_buf)); + ring_init (&usart_tx_ring, usart_tx_ring_buf, sizeof (usart_tx_ring_buf)); + /* Enable the USART1 interrupt. */ + nvic_enable_irq (NVIC_USART1_IRQ); + /* Map pins */ + gpio_set_mode (GPIOA, GPIO_MODE_OUTPUT_50_MHZ, + GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART1_TX); + gpio_set_mode (GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, + GPIO_USART1_RX); + /* Setup UART1 parameters. */ + usart_set_baudrate (USART1, 115200); + usart_set_databits (USART1, 8); + usart_set_stopbits (USART1, USART_STOPBITS_1); + usart_set_parity (USART1, USART_PARITY_NONE); + usart_set_flow_control (USART1, USART_FLOWCONTROL_NONE); + usart_set_mode (USART1, USART_MODE_TX_RX); + /* Enable USART1 Receive interrupt. */ + USART_CR1 (USART1) |= USART_CR1_RXNEIE; + /* Finally enable USART1. */ + usart_enable (USART1); +} -- cgit v1.2.3