From 7ebfa0fcb01b69218de8c3adde6eb17c48e521f7 Mon Sep 17 00:00:00 2001 From: eddyem Date: Wed, 23 Jul 2014 17:42:12 +0400 Subject: [PATCH] Added USART support (Up to three USARTs) --- with_opencm3/cdcacm.c | 51 +++++-- with_opencm3/cdcacm.h | 8 +- with_opencm3/hardware_ini.c | 41 ++++++ with_opencm3/hardware_ini.h | 29 ++++ with_opencm3/ircontroller.bin | Bin 6364 -> 7452 bytes with_opencm3/main.c | 23 +++- with_opencm3/main.h | 10 +- with_opencm3/uart.c | 252 ++++++++++++++++++++++++++++++++++ with_opencm3/uart.h | 37 +++++ with_opencm3/user_proto.c | 32 ++++- 10 files changed, 455 insertions(+), 28 deletions(-) create mode 100644 with_opencm3/hardware_ini.c create mode 100644 with_opencm3/hardware_ini.h create mode 100644 with_opencm3/uart.c create mode 100644 with_opencm3/uart.h diff --git a/with_opencm3/cdcacm.c b/with_opencm3/cdcacm.c index 04afdd1..c2c32fa 100644 --- a/with_opencm3/cdcacm.c +++ b/with_opencm3/cdcacm.c @@ -20,11 +20,14 @@ #include "cdcacm.h" #include "user_proto.h" +#include "main.h" +#include "uart.h" // Buffer for USB Tx static uint8_t USB_Tx_Buffer[USB_TX_DATA_SIZE]; static uint8_t USB_Tx_ptr = 0; - +// connection flag +uint8_t USB_connected = 0; static const struct usb_device_descriptor dev = { .bLength = USB_DT_DEVICE_SIZE, .bDescriptorType = USB_DT_DEVICE, @@ -176,6 +179,11 @@ struct usb_cdc_line_coding linecoding = { /* Buffer to be used for control requests. */ uint8_t usbd_control_buffer[128]; +/** + * This function runs every time it gets a request for control parameters get/set + * parameter SET_LINE_CODING used to change USART1 parameters: if you want to + * change them, just connect through USB with required parameters + */ static int cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req)) { @@ -183,9 +191,20 @@ static int cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data * (void)buf; (void)usbd_dev; char local_buf[10]; + struct usb_cdc_line_coding lc; switch (req->bRequest) { case SET_CONTROL_LINE_STATE:{ +//P("SET_CONTROL_LINE_STATE\r\n", uart1_send); +//print_int(req->wValue, uart1_send); +//newline(uart1_send); + if(req->wValue){ // terminal is opened + USB_connected = 1; + //P("\r\n\tUSB connected!\r\n", uart1_send); + }else{ // terminal is closed + USB_connected = 0; + //P("\r\n\tUSB disconnected!\r\n", uart1_send); + } /* * This Linux cdc_acm driver requires this to be implemented * even though it's optional in the CDC spec, and we don't @@ -203,14 +222,28 @@ static int cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data * usbd_ep_write_packet(usbd_dev, 0x83, local_buf, 10); }break; case SET_LINE_CODING: - if (*len != sizeof(struct usb_cdc_line_coding)) +//P("SET_LINE_CODING, len=", uart1_send); + if (!len || (*len != sizeof(struct usb_cdc_line_coding))) return 0; - memcpy((void *)&linecoding, (void *)*buf, *len); +//print_int(*len, uart1_send); +//newline(uart1_send); + memcpy((void *)&lc, (void *)*buf, *len); + // Mark & Space parity don't support by hardware, check it + if(lc.bParityType == USB_CDC_MARK_PARITY || lc.bParityType == USB_CDC_SPACE_PARITY){ + return 0; // error + }else{ + memcpy((void *)&linecoding, (void *)&lc, sizeof(struct usb_cdc_line_coding)); + UART_setspeed(USART1, &linecoding); + } break; - case GET_LINE_CODING: - usbd_ep_write_packet(usbd_dev, 0x82, (char*)&linecoding, sizeof(linecoding)); + case GET_LINE_CODING: // return linecoding buffer + if(len && *len == sizeof(struct usb_cdc_line_coding)) + memcpy((void *)*buf, (void *)&linecoding, sizeof(struct usb_cdc_line_coding)); + //usbd_ep_write_packet(usbd_dev, 0x83, (char*)&linecoding, sizeof(linecoding)); +//P("GET_LINE_CODING\r\n", uart1_send); break; default: +//P("UNKNOWN\r\n", uart1_send); return 0; } return 1; @@ -218,10 +251,8 @@ static int cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data * static void cdcacm_data_rx_cb(usbd_device *usbd_dev, uint8_t ep){ (void)ep; - char buf[64]; int len = usbd_ep_read_packet(usbd_dev, 0x01, buf, 64); - if(len > 0) parce_incoming_buf(buf, len, usb_send); } @@ -263,12 +294,16 @@ usbd_device *USB_init(){ * @param byte - a byte to put into a buffer */ void usb_send(uint8_t byte){ - if(!current_usb) return; + //if(!USB_connected) return; USB_Tx_Buffer[USB_Tx_ptr++] = byte; if(USB_Tx_ptr == USB_TX_DATA_SIZE) // buffer can be overflowed - send it! usb_send_buffer(); } +/** + * Send all data in buffer over USB + * this function runs when buffer is full or on SysTick + */ void usb_send_buffer(){ if(USB_Tx_ptr){ if(current_usb) diff --git a/with_opencm3/cdcacm.h b/with_opencm3/cdcacm.h index 6dd007f..90c162c 100644 --- a/with_opencm3/cdcacm.h +++ b/with_opencm3/cdcacm.h @@ -23,12 +23,7 @@ #ifndef __CCDCACM_H__ #define __CCDCACM_H__ -#include -#include // memcpy -#include -#include #include -#include // commands through EP0 #define SEND_ENCAPSULATED_COMMAND 0x00 @@ -44,6 +39,9 @@ // Size of buffer to output #define USB_TX_DATA_SIZE 64 +// USB connection flag +extern uint8_t USB_connected; +extern struct usb_cdc_line_coding linecoding; usbd_device *USB_init(); void usb_send(uint8_t byte); diff --git a/with_opencm3/hardware_ini.c b/with_opencm3/hardware_ini.c new file mode 100644 index 0000000..f3d03e8 --- /dev/null +++ b/with_opencm3/hardware_ini.c @@ -0,0 +1,41 @@ +/* + * hardware_ini.c - functions for HW initialisation + * + * Copyright 2014 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "main.h" +#include "hardware_ini.h" + +/** + * GPIO initialisaion: clocking + ports setup + */ +void GPIO_init(){ + rcc_periph_clock_enable(RCC_GPIOC); + gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_2_MHZ, + GPIO_CNF_OUTPUT_PUSHPULL, GPIO11|GPIO12); // LED + USB +} + +void SysTick_init(){ + systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8); // Systyck: 72/8=9MHz + systick_set_reload(8999); // 9000 pulses: 1kHz + systick_interrupt_enable(); + systick_counter_enable(); +} + + diff --git a/with_opencm3/hardware_ini.h b/with_opencm3/hardware_ini.h new file mode 100644 index 0000000..3578585 --- /dev/null +++ b/with_opencm3/hardware_ini.h @@ -0,0 +1,29 @@ +/* + * hardware_ini.h + * + * Copyright 2014 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#pragma once +#ifndef __HARDWARE_INI_H__ +#define __HARDWARE_INI_H__ + +void GPIO_init(); +void SysTick_init(); + +#endif // __HARDWARE_INI_H__ diff --git a/with_opencm3/ircontroller.bin b/with_opencm3/ircontroller.bin index 5bea2ec9236266dadf697408689e81d8a4eaa1bf..ae457dce1f31c6c2ab69306c1fc8d8b1a3ec55ae 100755 GIT binary patch delta 2613 zcmb7Ge{2)i9sj<&vwbmka1ufs+l;f1gajL!gh3M+<_j|Vf@gsPRtoF zC1}H;X(gsAYU!1VLaL2znt&EHB(hX~ScXxyv2~N(4Gl&mZbB1unYx2I_~L|k-{)i% z0%>d~eeU~x-yiS3pZ9(5*`GEJu86~W5H2}^Pa%?z0Ump33ue#nw_uV%gBr1i^;1fC zlq2m?t=ce25a>)V4lGHVuiFE`v_G&QZ4Io-tkOCIbJEQ9VBpz|Rr_{;iKq7lnlfHZ z?1*OjHh|tV8PJ3oeaU34rg*N5@}y%8Y5AQ2LxtR;!eXaeTiL_-t1?7ni&}Yx6IaF@ zT17{rT*z4py}`)pZp1O-P?PELWgdVwGhwUcF>#zk)#&Y#{g0z+(D+X=Oit%|>m z>u?f4co*eyL?;8hBN5HE#z22&lIvi+;EQH2ZcN^FNTC1n95{%?CqN+jZ}Y+X3mb@j zAy4!_=971MiRho4t4KH^#0x6plSEDi{rO3IM36y!*-I^;w@rcwsv!4!S)W6MxV~!A zi~(M6+{X+}f5e=;!2y5R1bjWp`H8hX-oVPVFTkXQz#3e$$U!k&afaa1gH{nc?i(;T zLBO|30AHDW+As^J4PIb%mSudW4XZF<*ct{5yMvtS_gb+8@1&@)BkqG1|GZ4RLfPEw zQ8Hg4_0Ha7y_GjgJNa%~SGfDNZd(WFy+*0_(is|R%~U9saG6rwb?D$beQ)+2?Is!s zpb>!^awO>r5(G382@;2fi1#}(WqW^u$j&p0%!CWMOH*Y-kc8A;BsM?6;wo4pR;h!i zeIlclbXvpK2nj+>-SI@y0NYf|7(jr%kWD2=ksaQLWq5eYdda5~5^*pwz-kGw? z^$O^B@+W(-U3xC>M@d%R947vwsoCKsqrw4R(6jlM9+EP;!%}Tg=ujV_D z$FK7ezAxvO$}DccX4F@W*U3cRKTgXn96CS( z9$RW7601C$c*o4i)z?5*^NS(_h6M(L)-*d7i-!h-T>9r@dr-DzSZzU=K>)&j&jJKL zbN-_|r; zcQ}Q998>*usv~o%|Cs8SXCxLzOxUm@&(M(>nn!}Ij}{vj=ZAv}xCwT_TlmShup@ta zf!3!6nY83*)0`&xO&QQ!XFz-fBj#(P#X?8BFgEs_Y|@UuSclC1K2DZD7+$?3cLQp< z8QV>?eKCAKnEMmWl^STiksMV*NOZKzNYWzXMK&_6`$Vy7Qq+Go&8Dai7Fos;pf4Ur zb`R&`T?<=4SH|i6TaHJ4`*=C#4^81+JB2u8~W8DFZn z-6LcB;<+1aN7Ro~aAW)SfG&^!>khpk>5_g(K;RRFT>TUiaVez9)x{@2BqRGx0z>wz zKe23#1DL~>$Qwbo!llf(Kgei^?SzqudtdZ-#oFl{bFfWL#ASuAx242v-^LK)GJ4sa zVpiH%9U@y|?UxlXdvR-Z=n~pd*KO>y9-=Y3t3$2Dm{1mqnO99$?X4IonUssBi*{AF z)T&N?t#v~w@E;(S%^umshdHuaJ!@+vUsoq=t4Wi((q2#IsoU*sB(J__KSp+_?WF@H zgLtZ&@q(VECQGZB?|Re+rAw@C2k@H^ZH|#8v;WF4zhG2r`33T}`kV3^<^mb{ynHiZ zKJuvHIXkFtc+NUpkl4t5z^6w`y_L*uV@NG=RV&L$%Q<#^Kg%;4_F(#LRqO z3bh>g?HEZ7N%X%)V;GzPdw*pv@ZA-_kE1+*GJ)8Ff8Dz0;60C6RSA40`o5eD6$XAq U>*PzYE-&I4j}-&T_W{Mf0gjnP*Z=?k delta 1540 zcmb_cT}&KR6h8OPzz)j-y9;3lcC|A*pcGhLrJ9shp<5VWhd-qc^`{X{G}|U5i_wOX zCW~M!#uC$Bo7BIgCK{`eWY^6`t0lDRgZkpGn)ruy5>0AjO-DoB*%dpULF@xO^g$>2 z=A3)ach0$I&YAmC`_e557zXK74G8ZbGV1{A9-Cvs-nQjf$wr^`F|M&rY)EnVR zl5_svq2;N&z?doqba72TSgh4YBY}^85lC+r+4`voNh{xOHHhVU+XQWK~pAI^))e42%Xl6Ws_<-MCH^OVKXNi6Bib{Os-oqxb!nIS{_*K{$&NGDng`-ly8Whl@lN zQ!$lBt^5O)CkYF%m_pvBO#g)3+MLJ+TWMBm4dv?eSCl!E4@>wi34>Cv&YPv-c~b~e zW!`j#wb?ndLgEaLn=@VE8JWE4R4R4<-Jk=f^`jvjbnoYzaD)3O88 z_Y{c)I!Judjfn|>v?;@3F;30dOW2gcoF&f0uLWnnG%BUa`oL)ZONv?N|DiV_{jdna zdssi--ZN(VcNbt0!vIovG5OJ0_;4<&r2E75Jr;xSi_c8uty94$U7MNjaj9 zzUqmOcagU5-tKIvj+2~~Us{a!Kw{AjYCG6uEC2aoJOjqI!qD=LI2cbAAUL#qX2jo1 zWiTRU9Zmr}2*y~!w>A&^3ReE8g}Z!-iZyOu$=QsmUNH6)B$XJIX5{x9!^EH_F=`O? zX4zm9w)we2Tg>lIUk*qmtJ z1JbliqGUT$%178rc>@I;4p+ak&k4foh){WYzbnd@UQb&^cEx*>v)Tp10OAf;`u6H?DP1DWTYH)uW1rPF(q%~h zQF||;Pm1hr@e$kho;cWk$#V6(2B^NvrV zL15znB>`Wd_6g!g#9ExI;+aYi_F#qfMh5LOHirU+h0+Bt2z#qQ_zmR&l=Fyt@Fw2t j2H`ctZ5|LR&~`N#Dil7j&nM*Ya2F7HA2tBIlVIa-!6B~S diff --git a/with_opencm3/main.c b/with_opencm3/main.c index 33b7419..c01d445 100644 --- a/with_opencm3/main.c +++ b/with_opencm3/main.c @@ -20,6 +20,9 @@ */ #include "main.h" +#include "hardware_ini.h" +#include "cdcacm.h" +#include "uart.h" uint32_t Timer = 0; // global timer (milliseconds) @@ -29,24 +32,27 @@ int main(){ usbd_device *usbd_dev; //rcc_clock_setup_in_hsi_out_48mhz(); + // RCC clocking: 8MHz oscillator -> 72MHz system rcc_clock_setup_in_hse_8mhz_out_72mhz(); - rcc_periph_clock_enable(RCC_GPIOC); - gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_2_MHZ, - GPIO_CNF_OUTPUT_PUSHPULL, GPIO11|GPIO12); + // GPIO + GPIO_init(); gpio_set(GPIOC, GPIO11); // turn off USB gpio_clear(GPIOC, GPIO12); // turn on LED + // init USART1 + UART_init(USART1); + + // USB usbd_dev = USB_init(); + // wait a little and then turn on USB pullup for (i = 0; i < 0x800000; i++) __asm__("nop"); gpio_clear(GPIOC, GPIO11); - systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8); // Systyck: 72/8=9MHz - systick_set_reload(8999); // 9000 pulses: 1kHz - systick_interrupt_enable(); - systick_counter_enable(); + // SysTick is a system timer with 1mc period + SysTick_init(); while(1){ usbd_poll(usbd_dev); @@ -58,6 +64,9 @@ int main(){ } } +/** + * SysTick interrupt: increment global time & send data buffer through USB + */ void sys_tick_handler(){ usb_send_buffer(); Timer++; diff --git a/with_opencm3/main.h b/with_opencm3/main.h index d756575..18086cd 100644 --- a/with_opencm3/main.h +++ b/with_opencm3/main.h @@ -24,8 +24,16 @@ #ifndef __MAIN_H__ #define __MAIN_H__ -#include "cdcacm.h" +#include +#include // memcpy +#include +#include +#include +#include +#include #include +#include + #include "user_proto.h" #endif // __MAIN_H__ diff --git a/with_opencm3/uart.c b/with_opencm3/uart.c new file mode 100644 index 0000000..60b64e9 --- /dev/null +++ b/with_opencm3/uart.c @@ -0,0 +1,252 @@ +/* + * uart.c - functions to work with UART + * + * Copyright 2014 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "main.h" +#include "uart.h" +#include "cdcacm.h" + +// Buffers for Tx +typedef struct { + uint8_t buf[UART_TX_DATA_SIZE]; + uint8_t start; // index from where to start reading + uint8_t end; // index from where to start writing +} UART_buff; +static UART_buff TX_buffer[3]; // buffers for all three ports + +void fill_uart_buff(uint32_t UART, uint8_t byte); + +/** + * Set UART speed + * @param lc - UART parameters or NULL for value from cdcacm.c (started - B115200,8,N,1) + */ +void UART_setspeed(uint32_t UART, struct usb_cdc_line_coding *lc){ + uint32_t tmp; + if(!lc) lc = &linecoding; // default linecoding from cdcacm.c + usart_set_baudrate(UART, lc->dwDTERate); + usart_set_databits(UART, lc->bDataBits); + switch(lc->bCharFormat){ + case USB_CDC_1_5_STOP_BITS: + tmp = USART_STOPBITS_1_5; + break; + case USB_CDC_2_STOP_BITS: + tmp = USART_STOPBITS_2; + break; + case USB_CDC_1_STOP_BITS: + default: + tmp = USART_STOPBITS_1; + } + usart_set_stopbits(UART, tmp); + switch(lc->bParityType){ + case USB_CDC_ODD_PARITY: + tmp = USART_PARITY_ODD; + break; + case USB_CDC_EVEN_PARITY: + tmp = USART_PARITY_EVEN; + break; + case USB_CDC_NO_PARITY: + default: + tmp = USART_PARITY_NONE; + } + usart_set_parity(UART, tmp); + usart_set_flow_control(UART, USART_FLOWCONTROL_NONE); + usart_set_mode(UART, USART_MODE_TX_RX); +} + +/** + * Setup UART + */ +void UART_init(uint32_t UART){ + uint32_t irq, rcc, rccgpio, gpioport, gpiopin; + switch(UART){ + case USART2: + irq = NVIC_USART2_IRQ; // interrupt for given USART + rcc = RCC_USART2; // RCC timing of USART + rccgpio = RCC_GPIOA; // RCC timing of GPIO pin (for output) + TX_buffer[1].end = 0; // reset counters + TX_buffer[1].start = 0; + // output pin setup + gpioport = GPIO_BANK_USART2_TX; + gpiopin = GPIO_USART2_TX; + break; + case USART3: + irq = NVIC_USART3_IRQ; + rcc = RCC_USART3; + rccgpio = RCC_GPIOB; + TX_buffer[2].end = 0; + TX_buffer[2].start = 0; + gpioport = GPIO_BANK_USART3_TX; + gpiopin = GPIO_USART3_TX; + break; + case USART1: + default: + irq = NVIC_USART1_IRQ; + rcc = RCC_USART1; + rccgpio = RCC_GPIOA; + TX_buffer[0].end = 0; + TX_buffer[0].start = 0; + gpioport = GPIO_BANK_USART1_TX; + gpiopin = GPIO_USART1_TX; + } + // enable clocking + rcc_periph_clock_enable(RCC_AFIO); // alternate functions + rcc_periph_clock_enable(rcc); // USART + rcc_periph_clock_enable(rccgpio); // output pin + // enable output pin + gpio_set_mode(gpioport, GPIO_MODE_OUTPUT_50_MHZ, + GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, gpiopin); + // enable IRQ + nvic_enable_irq(irq); + UART_setspeed(UART, NULL); + // Enable UART receive interrupt + USART_CR1(UART) |= USART_CR1_RXNEIE; + // Enable UART + usart_enable(UART); +} + +/* + * UART interrupts + */ +// common +void UART_isr(uint32_t UART){ + uint8_t bufidx = 0, data; + UART_buff *curbuff; + sendfun sf = uart1_send; + // Check if we were called because of RXNE + if(USART_SR(UART) & USART_SR_RXNE){ + // parce incoming byte + data = usart_recv(UART); + switch(UART){ + case USART1: + sf = uart1_send; + break; + case USART2: + sf = uart2_send; + break; + case USART3: + sf = uart3_send; + break; + default: // error - return + return; + } + parce_incoming_buf((char*)&data, 1, sf); + //fill_uart_buff(UART, data); + } + // Check if we were called because of TXE + if((USART_CR1(USART1) & USART_CR1_TXEIE) && (USART_SR(UART) & USART_SR_TXE)){ + switch(UART){ + case USART1: + bufidx = 0; + break; + case USART2: + bufidx = 1; + break; + case USART3: + bufidx = 2; + break; + default: // error - return + return; + } + curbuff = &TX_buffer[bufidx]; + bufidx = curbuff->start; // start of data in buffer + if(bufidx != curbuff->end){ // there's data in buffer + // Put data into the transmit register + usart_send(UART, curbuff->buf[bufidx]); + if(++(curbuff->start) == UART_TX_DATA_SIZE) // bufidx > endidx && got end of buffer + curbuff->start = 0; + }else{ // Disable the TXE interrupt, it's no longer needed + USART_CR1(UART) &= ~USART_CR1_TXEIE; + // empty indexes + curbuff->start = 0; + curbuff->end = 0; + } + } +} +// particular +void usart1_isr(){ + UART_isr(USART1); +} +void usart2_isr(){ + UART_isr(USART2); +} +void usart3_isr(){ + UART_isr(USART3); +} + +// put data into buffer +void fill_uart_buff(uint32_t UART, uint8_t byte){ + UART_buff *curbuff; + uint8_t bufidx = 0, endidx; + switch(UART){ + case USART1: + bufidx = 0; + break; + case USART2: + bufidx = 1; + break; + case USART3: + bufidx = 2; + break; + default: // error - return + return; + } + curbuff = &TX_buffer[bufidx]; + bufidx = curbuff->start; // start of data in buffer + endidx = curbuff->end; // end of data + curbuff->buf[endidx++] = byte; // put byte into buffer + // now check indexes + if(endidx != bufidx && endidx != UART_TX_DATA_SIZE){ // all OK - there's enough place for data + (curbuff->end)++; // just increment index in buffer + }else{ // dangerous situation: possible overflow + if(endidx == UART_TX_DATA_SIZE){ // end of buffer + if(bufidx != 0){ // no overflow + curbuff->end = 0; + goto end_of_fn; + } + } + // overflow: purge all data + USART_CR1(UART) &= ~USART_CR1_TXEIE; // disable TX interrupt - all will be done "by hands" + bufidx = curbuff->start; // refresh data index + for(endidx = bufidx; endidx < UART_TX_DATA_SIZE; endidx++) // first data porion + usart_send(UART, curbuff->buf[endidx]); + for(endidx = 0; endidx < bufidx; endidx++) // rest of data + usart_send(UART, curbuff->buf[endidx]); + curbuff->start = 0; + curbuff->end = 0; + return; + } + end_of_fn: + // enable interrupts to send data from buffer + USART_CR1(UART) |= USART_CR1_TXEIE; +} +/** + * send data over UART - one function for each uart + * @param byte - one byte to put in UART queue + */ +void uart1_send(uint8_t byte){ + fill_uart_buff(USART1, byte); +} +void uart2_send(uint8_t byte){ + fill_uart_buff(USART2, byte); +} +void uart3_send(uint8_t byte){ + fill_uart_buff(USART3, byte); +} + diff --git a/with_opencm3/uart.h b/with_opencm3/uart.h new file mode 100644 index 0000000..ad6e239 --- /dev/null +++ b/with_opencm3/uart.h @@ -0,0 +1,37 @@ +/* + * uart.h + * + * Copyright 2014 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#pragma once +#ifndef __UART_H__ +#define __UART_H__ + +// Size of buffers +#define UART_TX_DATA_SIZE 64 + +void UART_init(uint32_t UART); +void UART_setspeed(uint32_t UART, struct usb_cdc_line_coding *linecoding); + +void uart1_send(uint8_t byte); +void uart2_send(uint8_t byte); +void uart3_send(uint8_t byte); + + +#endif // __UART_H__ diff --git a/with_opencm3/user_proto.c b/with_opencm3/user_proto.c index c9367da..14b89a4 100644 --- a/with_opencm3/user_proto.c +++ b/with_opencm3/user_proto.c @@ -20,7 +20,8 @@ */ #include "cdcacm.h" -#include "user_proto.h" +#include "main.h" +#include "uart.h" // integer value given by user static volatile int32_t User_value = 0; @@ -46,15 +47,18 @@ void parce_incoming_buf(char *buf, int len, sendfun s){ int i = 0; if(Uval_ready == UVAL_START){ // we are in process of user's value reading i += read_int(buf, len); - }else{ - if(Uval_ready == UVAL_ENTERED){ - print_int(User_value, s); // printout readed integer value for error control - Uval_ready = UVAL_PRINTED; - } - if(I && Uval_ready == UVAL_CHECKED) I(User_value, s); + } + if(Uval_ready == UVAL_ENTERED){ + print_int(User_value, s); // printout readed integer value for error control + Uval_ready = UVAL_PRINTED; + } + if(I && Uval_ready == UVAL_CHECKED){ + Uval_ready = UVAL_BAD; // clear Uval_ready + I(User_value, s); } for(; i < len; i++){ command = buf[i]; + if(!command) continue; // omit zero switch (command){ case 'b': // turn LED off gpio_set(GPIOC, GPIO12); @@ -74,6 +78,20 @@ void parce_incoming_buf(char *buf, int len, sendfun s){ if(Uval_ready == UVAL_PRINTED) Uval_ready = UVAL_BAD; else WRONG_COMMAND(); break; + case 'u': // check USB connection + P("\r\nUSB ", s); + if(!USB_connected) P("dis", s); + P("connected\r\n",s); + break; +/* + case 'U': // test: init USART1 + UART_init(USART1); + break; +*/ + case '\n': // show newline as is + break; + case '\r': + break; default: WRONG_COMMAND(); // echo '?' on unknown command }