diff --git a/Core/user/printf.c b/Core/user/printf.c new file mode 100644 index 0000000..b856150 --- /dev/null +++ b/Core/user/printf.c @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2004,2012 Kustaa Nyholm / SpareTimeLabs + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * Neither the name of the Kustaa Nyholm or SpareTimeLabs nor the names of its + * contributors may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +#include "printf.h" + +typedef void (*putcf) (void*,char); +static putcf stdout_putf; +static void* stdout_putp; + + +#ifdef PRINTF_LONG_SUPPORT + +static void uli2a(unsigned long int num, unsigned int base, int uc,char * bf) + { + int n=0; + unsigned int d=1; + while (num/d >= base) + d*=base; + while (d!=0) { + int dgt = num / d; + num%=d; + d/=base; + if (n || dgt>0|| d==0) { + *bf++ = dgt+(dgt<10 ? '0' : (uc ? 'A' : 'a')-10); + ++n; + } + } + *bf=0; + } + +static void li2a (long num, char * bf) + { + if (num<0) { + num=-num; + *bf++ = '-'; + } + uli2a(num,10,0,bf); + } + +#endif + +static void ui2a(unsigned int num, unsigned int base, int uc,char * bf) + { + int n=0; + unsigned int d=1; + while (num/d >= base) + d*=base; + while (d!=0) { + int dgt = num / d; + num%= d; + d/=base; + if (n || dgt>0 || d==0) { + *bf++ = dgt+(dgt<10 ? '0' : (uc ? 'A' : 'a')-10); + ++n; + } + } + *bf=0; + } + +static void i2a (int num, char * bf) + { + if (num<0) { + num=-num; + *bf++ = '-'; + } + ui2a(num,10,0,bf); + } + +static int a2d(char ch) + { + if (ch>='0' && ch<='9') + return ch-'0'; + else if (ch>='a' && ch<='f') + return ch-'a'+10; + else if (ch>='A' && ch<='F') + return ch-'A'+10; + else return -1; + } + +static char a2i(char ch, const char** src,int base,int* nump) + { + const char* p= *src; + int num=0; + int digit; + while ((digit=a2d(ch))>=0) { + if (digit>base) break; + num=num*base+digit; + ch=*p++; + } + *src=p; + *nump=num; + return ch; + } + +static void putchw(void* putp,putcf putf,int n, char z, char* bf) + { + char fc=z? '0' : ' '; + char ch; + char* p=bf; + while (*p++ && n > 0) + n--; + while (n-- > 0) + putf(putp,fc); + while ((ch= *bf++)) + putf(putp,ch); + } + +void tfp_format(void* putp,putcf putf,const char *fmt, va_list va) + { + char bf[12]; + + char ch; + + + while ((ch=*(fmt++))) { + if (ch!='%') + putf(putp,ch); + else { + char lz=0; +#ifdef PRINTF_LONG_SUPPORT + char lng=0; +#endif + int w=0; + ch=*(fmt++); + if (ch=='0') { + ch=*(fmt++); + lz=1; + } + if (ch>='0' && ch<='9') { + ch=a2i(ch,&fmt,10,&w); + } +#ifdef PRINTF_LONG_SUPPORT + if (ch=='l') { + ch=*(fmt++); + lng=1; + } +#endif + switch (ch) { + case 0: + goto abort; + case 'u' : { +#ifdef PRINTF_LONG_SUPPORT + if (lng) + uli2a(va_arg(va, unsigned long int),10,0,bf); + else +#endif + ui2a(va_arg(va, unsigned int),10,0,bf); + putchw(putp,putf,w,lz,bf); + break; + } + case 'd' : { +#ifdef PRINTF_LONG_SUPPORT + if (lng) + li2a(va_arg(va, unsigned long int),bf); + else +#endif + i2a(va_arg(va, int),bf); + putchw(putp,putf,w,lz,bf); + break; + } + case 'x': case 'X' : +#ifdef PRINTF_LONG_SUPPORT + if (lng) + uli2a(va_arg(va, unsigned long int),16,(ch=='X'),bf); + else +#endif + ui2a(va_arg(va, unsigned int),16,(ch=='X'),bf); + putchw(putp,putf,w,lz,bf); + break; + case 'c' : + putf(putp,(char)(va_arg(va, int))); + break; + case 's' : + putchw(putp,putf,w,0,va_arg(va, char*)); + break; + case '%' : + putf(putp,ch); + default: + break; + } + } + } + abort:; + } + + +void init_printf(void* putp,void (*putf) (void*,char)) + { + stdout_putf=putf; + stdout_putp=putp; + } + +void tfp_printf(const char *fmt, ...) + { + va_list va; + va_start(va,fmt); + tfp_format(stdout_putp,stdout_putf,fmt,va); + va_end(va); + } + +static void putcp(void* p,char c) + { + *(*((char**)p))++ = c; + } + + + +void tfp_sprintf(char* s,char *fmt, ...) + { + va_list va; + va_start(va,fmt); + tfp_format(&s,putcp,fmt,va); + putcp(&s,0); + va_end(va); + } + + diff --git a/Core/user/printf.h b/Core/user/printf.h new file mode 100644 index 0000000..b6db09c --- /dev/null +++ b/Core/user/printf.h @@ -0,0 +1,124 @@ +/* +File: printf.h + +Copyright (c) 2004,2012 Kustaa Nyholm / SpareTimeLabs + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or other +materials provided with the distribution. + +Neither the name of the Kustaa Nyholm or SpareTimeLabs nor the names of its +contributors may be used to endorse or promote products derived from this software +without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. + +---------------------------------------------------------------------- + +This library is realy just two files: 'printf.h' and 'printf.c'. + +They provide a simple and small (+200 loc) printf functionality to +be used in embedded systems. + +I've found them so usefull in debugging that I do not bother with a +debugger at all. + +They are distributed in source form, so to use them, just compile them +into your project. + +Two printf variants are provided: printf and sprintf. + +The formats supported by this implementation are: 'd' 'u' 'c' 's' 'x' 'X'. + +Zero padding and field width are also supported. + +If the library is compiled with 'PRINTF_SUPPORT_LONG' defined then the +long specifier is also +supported. Note that this will pull in some long math routines (pun intended!) +and thus make your executable noticably longer. + +The memory foot print of course depends on the target cpu, compiler and +compiler options, but a rough guestimate (based on a H8S target) is about +1.4 kB for code and some twenty 'int's and 'char's, say 60 bytes of stack space. +Not too bad. Your milage may vary. By hacking the source code you can +get rid of some hunred bytes, I'm sure, but personally I feel the balance of +functionality and flexibility versus code size is close to optimal for +many embedded systems. + +To use the printf you need to supply your own character output function, +something like : + +void putc ( void* p, char c) + { + while (!SERIAL_PORT_EMPTY) ; + SERIAL_PORT_TX_REGISTER = c; + } + +Before you can call printf you need to initialize it to use your +character output function with something like: + +init_printf(NULL,putc); + +Notice the 'NULL' in 'init_printf' and the parameter 'void* p' in 'putc', +the NULL (or any pointer) you pass into the 'init_printf' will eventually be +passed to your 'putc' routine. This allows you to pass some storage space (or +anything realy) to the character output function, if necessary. +This is not often needed but it was implemented like that because it made +implementing the sprintf function so neat (look at the source code). + +The code is re-entrant, except for the 'init_printf' function, so it +is safe to call it from interupts too, although this may result in mixed output. +If you rely on re-entrancy, take care that your 'putc' function is re-entrant! + +The printf and sprintf functions are actually macros that translate to +'tfp_printf' and 'tfp_sprintf'. This makes it possible +to use them along with 'stdio.h' printf's in a single source file. +You just need to undef the names before you include the 'stdio.h'. +Note that these are not function like macros, so if you have variables +or struct members with these names, things will explode in your face. +Without variadic macros this is the best we can do to wrap these +fucnction. If it is a problem just give up the macros and use the +functions directly or rename them. + +For further details see source code. + +regs Kusti, 23.10.2004 +*/ + + +#ifndef __TFP_PRINTF__ +#define __TFP_PRINTF__ + +#include + +void init_printf(void* putp,void (*putf) (void*,char)); + +void tfp_printf(const char *fmt, ...); +void tfp_sprintf(char* s,char *fmt, ...); + +void tfp_format(void* putp,void (*putf) (void*,char),const char *fmt, va_list va); + +#define printf tfp_printf +#define sprintf tfp_sprintf + +#endif + + + diff --git a/Core/user/usart2_it.c b/Core/user/usart2_it.c new file mode 100644 index 0000000..d3edc99 --- /dev/null +++ b/Core/user/usart2_it.c @@ -0,0 +1,141 @@ +/***************************************************************************//** +* @file usart2_it.c +* @brief UART with interrupt and ring buffer +*//****************************************************************************/ + +#include "stm32f4xx_hal.h" +//------------------------------C library--------------------------------------- +#include +//----------------------------user includes------------------------------------- +#include "usart2_it.h" +#include "usart2_it_cfg.h" +//------------------------------------------------------------------------------ + + + + +/* Private typedefs ----------------------------------------------------------*/ + +/* Private macros ------------------------------------------------------------*/ + +//====== UART buffer defines =================================================== +#define USART2_RXBUF_MASK (USART2_RXBUF_SIZE - 1) +#define USART2_TXBUF_MASK (USART2_TXBUF_SIZE - 1) + +#if ( USART2_RXBUF_SIZE & USART2_RXBUF_MASK ) +#error RX buffer size is not a power of 2! +#endif + +#if ( USART2_TXBUF_SIZE & USART2_TXBUF_MASK ) +#error TX buffer size is not a power of 2! +#endif + + +/* Private variables ---------------------------------------------------------*/ + +//====== Variables for transmitter ============================================= +static uint8_t Usart2TxBuf[USART2_TXBUF_SIZE]; +static uint16_t Usart2TxWrIdx = 0; +static volatile uint16_t Usart2TxRdIdx = 0; + +//====== Variables for Receiver ================================================ +static uint8_t Usart2RxBuf[USART2_RXBUF_SIZE]; +static volatile uint16_t Usart2RxWrIdx = 0; +static volatile uint16_t Usart2RxRdIdx = 0; + + +/* Public variables ----------------------------------------------------------*/ + + +/* Functions -----------------------------------------------------------------*/ + + +/***************************************************************************//** +* @brief USART2 init +*//****************************************************************************/ +void Usart2_Init(void) { + USART2->CR1 |= USART_CR1_RXNEIE; // Enable RX interrupt +} + + +/***************************************************************************//** +* @brief USART2 interrupt handler +*//****************************************************************************/ +void USART2_IRQHandler(void) { + uint32_t statusreg = USART2->SR; // read interrupt flags + + if ((statusreg & USART_SR_RXNE)) { // RX interrupt + uint8_t d = USART2->DR; // read received byte + uint_fast16_t wr = Usart2RxWrIdx; + wr = (wr + 1) & USART2_RXBUF_MASK; // new write index + Usart2RxBuf[wr] = d; // received data to buffer + Usart2RxWrIdx = wr; // Store new index + } + + if ((statusreg & USART_SR_TXE)) { // TX interrupt + uint_fast16_t rd = Usart2TxRdIdx; + uint_fast16_t wr = Usart2TxWrIdx; + if (wr != rd) { // data in buffer + rd = (rd + 1) & USART2_TXBUF_MASK; // new read index + USART2->DR = Usart2TxBuf[rd]; // send data byte + Usart2TxRdIdx = rd; // Store new index + if (wr == rd) { // data buffer empty + USART2->CR1 &= ~USART_CR1_TXEIE; // INT disable + } + } + } +} + + +/***************************************************************************//** +* @brief Send byte to UART +* @param d: byte to send +*//****************************************************************************/ +void Usart2_PutByte(uint8_t d) { + uint_fast16_t wr = Usart2TxWrIdx; + wr = (wr + 1) & USART2_TXBUF_MASK; // new write index + if (wr == Usart2TxRdIdx) { // No free space in buffer (overflow) + return; // drop remaining data (Attention! Buffer overflow not signaled! Use bigger buffer) + } + Usart2TxBuf[wr] = d; // Store data in buffer + Usart2TxWrIdx = wr; // Store new index + USART2->CR1 |= USART_CR1_TXEIE; // Interrupt enable (start send) +} + + +/***************************************************************************//** +* @brief Send more data to UART +* @param src: data to send +* @param n: count of data +*//****************************************************************************/ +void Usart2_PutData (void* src, uint16_t n) { + uint8_t* p = src; + uint_fast16_t wr = Usart2TxWrIdx; + while (n) { + wr = (wr + 1) & USART2_TXBUF_MASK; // new write index + if (wr == Usart2TxRdIdx) { // No free space in buffer (overflow) + break; // drop remaining data (Attention! Buffer overflow not signaled! Use bigger buffer) + } + Usart2TxBuf[wr] = *p; // Store data in buffer + p++; + n--; + } + Usart2TxWrIdx = wr; // Store new index + USART2->CR1 |= USART_CR1_TXEIE; // Interrupt enable (start send) +} + +/***************************************************************************//** +* @brief Read data from UART RX buffer +* @return received character, -1: no data in RX buffer +*//****************************************************************************/ +int16_t Usart2_GetByte(void) { + uint_fast16_t rd = Usart2RxRdIdx; + if (rd != Usart2RxWrIdx) { // new data in buffer + rd = (rd + 1) & USART2_RXBUF_MASK; // new read index + Usart2RxRdIdx = rd; // store new index + return Usart2RxBuf[rd]; // return with data + }else { + return -1; // buffer empty + } +} + diff --git a/Core/user/usart2_it.h b/Core/user/usart2_it.h new file mode 100644 index 0000000..8520de7 --- /dev/null +++ b/Core/user/usart2_it.h @@ -0,0 +1,13 @@ +#ifndef __USART2_IT_H__ +#define __USART2_IT_H__ + +#include + +extern void Usart2_Init(void); +extern void Usart2_PutByte(uint8_t d); +extern void Usart2_PutData(void* src, uint16_t n); +extern int16_t Usart2_GetByte(void); + + +#endif + diff --git a/Core/user/usart2_it_cfg.h b/Core/user/usart2_it_cfg.h new file mode 100644 index 0000000..8ecc3f8 --- /dev/null +++ b/Core/user/usart2_it_cfg.h @@ -0,0 +1,10 @@ +#ifndef __USART2_IT_CFG_H__ +#define __USART2_IT_CFG_H__ + + +#define USART2_RXBUF_SIZE 1024 +#define USART2_TXBUF_SIZE 1024 + + + +#endif // __USART_CFG_H__ diff --git a/Core/user/usart6_it.c b/Core/user/usart6_it.c new file mode 100644 index 0000000..bcdaae3 --- /dev/null +++ b/Core/user/usart6_it.c @@ -0,0 +1,141 @@ +/***************************************************************************//** +* @file usart6_it.c +* @brief UART with interrupt and ring buffer +*//****************************************************************************/ + +#include "stm32f4xx_hal.h" +//------------------------------C library--------------------------------------- +#include +//----------------------------user includes------------------------------------- +#include "usart6_it.h" +#include "usart6_it_cfg.h" +//------------------------------------------------------------------------------ + + + + +/* Private typedefs ----------------------------------------------------------*/ + +/* Private macros ------------------------------------------------------------*/ + +//====== UART buffer defines =================================================== +#define USART6_RXBUF_MASK (USART6_RXBUF_SIZE - 1) +#define USART6_TXBUF_MASK (USART6_TXBUF_SIZE - 1) + +#if ( USART6_RXBUF_SIZE & USART6_RXBUF_MASK ) +#error RX buffer size is not a power of 2! +#endif + +#if ( USART6_TXBUF_SIZE & USART6_TXBUF_MASK ) +#error TX buffer size is not a power of 2! +#endif + + +/* Private variables ---------------------------------------------------------*/ + +//====== Variables for transmitter ============================================= +static uint8_t Usart6TxBuf[USART6_TXBUF_SIZE]; +static uint16_t Usart6TxWrIdx = 0; +static volatile uint16_t Usart6TxRdIdx = 0; + +//====== Variables for Receiver ================================================ +static uint8_t Usart6RxBuf[USART6_RXBUF_SIZE]; +static volatile uint16_t Usart6RxWrIdx = 0; +static volatile uint16_t Usart6RxRdIdx = 0; + + +/* Public variables ----------------------------------------------------------*/ + + +/* Functions -----------------------------------------------------------------*/ + + +/***************************************************************************//** +* @brief USART6 init +*//****************************************************************************/ +void Usart6_Init(void) { + USART6->CR1 |= USART_CR1_RXNEIE; // Enable RX interrupt +} + + +/***************************************************************************//** +* @brief USART6 interrupt handler +*//****************************************************************************/ +void USART6_IRQHandler(void) { + uint32_t statusreg = USART6->SR; // read interrupt flags + + if ((statusreg & USART_SR_RXNE)) { // RX interrupt + uint8_t d = USART6->DR; // read received byte + uint_fast16_t wr = Usart6RxWrIdx; + wr = (wr + 1) & USART6_RXBUF_MASK; // new write index + Usart6RxBuf[wr] = d; // received data to buffer + Usart6RxWrIdx = wr; // Store new index + } + + if ((statusreg & USART_SR_TXE)) { // TX interrupt + uint_fast16_t rd = Usart6TxRdIdx; + uint_fast16_t wr = Usart6TxWrIdx; + if (wr != rd) { // data in buffer + rd = (rd + 1) & USART6_TXBUF_MASK; // new read index + USART6->DR = Usart6TxBuf[rd]; // send data byte + Usart6TxRdIdx = rd; // Store new index + if (wr == rd) { // data buffer empty + USART6->CR1 &= ~USART_CR1_TXEIE; // INT disable + } + } + } +} + + +/***************************************************************************//** +* @brief Send byte to UART +* @param d: byte to send +*//****************************************************************************/ +void Usart6_PutByte(uint8_t d) { + uint_fast16_t wr = Usart6TxWrIdx; + wr = (wr + 1) & USART6_TXBUF_MASK; // new write index + if (wr == Usart6TxRdIdx) { // No free space in buffer (overflow) + return; // drop remaining data (Attention! Buffer overflow not signaled! Use bigger buffer) + } + Usart6TxBuf[wr] = d; // Store data in buffer + Usart6TxWrIdx = wr; // Store new index + USART6->CR1 |= USART_CR1_TXEIE; // Interrupt enable (start send) +} + + +/***************************************************************************//** +* @brief Send more data to UART +* @param src: data to send +* @param n: count of data +*//****************************************************************************/ +void Usart6_PutData (void* src, uint16_t n) { + uint8_t* p = src; + uint_fast16_t wr = Usart6TxWrIdx; + while (n) { + wr = (wr + 1) & USART6_TXBUF_MASK; // new write index + if (wr == Usart6TxRdIdx) { // No free space in buffer (overflow) + break; // drop remaining data (Attention! Buffer overflow not signaled! Use bigger buffer) + } + Usart6TxBuf[wr] = *p; // Store data in buffer + p++; + n--; + } + Usart6TxWrIdx = wr; // Store new index + USART6->CR1 |= USART_CR1_TXEIE; // Interrupt enable (start send) +} + +/***************************************************************************//** +* @brief Read data from UART RX buffer +* @return received character, -1: no data in RX buffer +*//****************************************************************************/ +int16_t Usart6_GetByte(void) { + uint_fast16_t rd = Usart6RxRdIdx; + if (rd != Usart6RxWrIdx) { // new data in buffer + rd = (rd + 1) & USART6_RXBUF_MASK; // new read index + Usart6RxRdIdx = rd; // store new index + return Usart6RxBuf[rd]; // return with data + }else { + return -1; // buffer empty + } +} + diff --git a/Core/user/usart6_it.h b/Core/user/usart6_it.h new file mode 100644 index 0000000..ac8c7a0 --- /dev/null +++ b/Core/user/usart6_it.h @@ -0,0 +1,13 @@ +#ifndef __USART6_IT_H__ +#define __USART6_IT_H__ + +#include + +extern void Usart6_Init(void); +extern void Usart6_PutByte(uint8_t d); +extern void Usart6_PutData(void* src, uint16_t n); +extern int16_t Usart6_GetByte(void); + + +#endif + diff --git a/Core/user/usart6_it_cfg.h b/Core/user/usart6_it_cfg.h new file mode 100644 index 0000000..7fe7db4 --- /dev/null +++ b/Core/user/usart6_it_cfg.h @@ -0,0 +1,10 @@ +#ifndef __USART6_IT_CFG_H__ +#define __USART6_IT_CFG_H__ + + +#define USART6_RXBUF_SIZE 1024 +#define USART6_TXBUF_SIZE 1024 + + + +#endif // __USART6_CFG_H__