From c07884c06d2dca55a2764f3766e8dbb810b64e34 Mon Sep 17 00:00:00 2001 From: eddyem Date: Fri, 10 Mar 2017 22:15:40 +0300 Subject: [PATCH] add TSYS01 --- F0-nolib/Readme.md | 1 + F0-nolib/tsys01_nucleo/Makefile | 137 +++++++++++++++++++++ F0-nolib/tsys01_nucleo/Readme | 5 + F0-nolib/tsys01_nucleo/i2c.c | 122 +++++++++++++++++++ F0-nolib/tsys01_nucleo/i2c.h | 39 ++++++ F0-nolib/tsys01_nucleo/ld/stm32f042k.ld | 12 ++ F0-nolib/tsys01_nucleo/main.c | 151 +++++++++++++++++++++++ F0-nolib/tsys01_nucleo/tsys01.bin | Bin 0 -> 2784 bytes F0-nolib/tsys01_nucleo/usart.c | 152 ++++++++++++++++++++++++ F0-nolib/tsys01_nucleo/usart.h | 48 ++++++++ 10 files changed, 667 insertions(+) create mode 100644 F0-nolib/tsys01_nucleo/Makefile create mode 100644 F0-nolib/tsys01_nucleo/Readme create mode 100644 F0-nolib/tsys01_nucleo/i2c.c create mode 100644 F0-nolib/tsys01_nucleo/i2c.h create mode 100644 F0-nolib/tsys01_nucleo/ld/stm32f042k.ld create mode 100644 F0-nolib/tsys01_nucleo/main.c create mode 100755 F0-nolib/tsys01_nucleo/tsys01.bin create mode 100644 F0-nolib/tsys01_nucleo/usart.c create mode 100644 F0-nolib/tsys01_nucleo/usart.h diff --git a/F0-nolib/Readme.md b/F0-nolib/Readme.md index 2d74344..1abf883 100644 --- a/F0-nolib/Readme.md +++ b/F0-nolib/Readme.md @@ -6,6 +6,7 @@ This directory contains examples for F0 without any library - blink - simple LED blink - htu21d_nucleo - operaing with HTU-21D in STM32F042-nucleo - morze - for STM32F030, echo data from USART1 on TIM3CH1 (PA6) as Morze code +- tsys01_nucleo - read two TSYS01 sensors using STM32F042 - uart - USART over DMA with hardware end-of-string detection - uart_blink - code for STM32F030F4, echo data on USART1 and blink LEDS on PA4 and PA5 - uart_nucleo - USART over DMA for STM32F042-nucleo diff --git a/F0-nolib/tsys01_nucleo/Makefile b/F0-nolib/tsys01_nucleo/Makefile new file mode 100644 index 0000000..d2a8296 --- /dev/null +++ b/F0-nolib/tsys01_nucleo/Makefile @@ -0,0 +1,137 @@ +BINARY = tsys01 +BOOTPORT ?= /dev/ttyUSB0 +BOOTSPEED ?= 115200 +# MCU FAMILY +FAMILY = F0 +# MCU code +MCU = F042x6 +DEFS += -DEBUG +# change this linking script depending on particular MCU model, +# for example, if you have STM32F103VBT6, you should write: +LDSCRIPT = ld/stm32f042k.ld + +INDEPENDENT_HEADERS= + +FP_FLAGS ?= -msoft-float +ASM_FLAGS = -mthumb -mcpu=cortex-m0 -march=armv6-m -mtune=cortex-m0 +ARCH_FLAGS = $(ASM_FLAGS) $(FP_FLAGS) + +############################################################################### +# Executables +PREFIX ?= /opt/bin/arm-none-eabi + +RM := rm -f +RMDIR := rmdir +CC := $(PREFIX)-gcc +LD := $(PREFIX)-gcc +AR := $(PREFIX)-ar +AS := $(PREFIX)-as +OBJCOPY := $(PREFIX)-objcopy +OBJDUMP := $(PREFIX)-objdump +GDB := $(PREFIX)-gdb +STFLASH := $(shell which st-flash) +STBOOT := $(shell which stm32flash) + +############################################################################### +# Source files +OBJDIR = mk +LDSCRIPT ?= $(BINARY).ld +SRC := $(wildcard *.c) +OBJS := $(addprefix $(OBJDIR)/, $(SRC:%.c=%.o)) +STARTUP = $(OBJDIR)/startup.o +OBJS += $(STARTUP) +DEPS := $(OBJS:.o=.d) + +INC_DIR ?= ../inc + +INCLUDE := -I$(INC_DIR)/F0 -I$(INC_DIR)/cm +LIB_DIR := $(INC_DIR)/ld + +############################################################################### +# C flags +CFLAGS += -O2 -g -MD -D__thumb2__=1 +CFLAGS += -Wall -Wextra -Wshadow -Wimplicit-function-declaration +CFLAGS += -Wredundant-decls $(INCLUDE) +# -Wmissing-prototypes -Wstrict-prototypes +CFLAGS += -fno-common -ffunction-sections -fdata-sections + +############################################################################### +# Linker flags +LDFLAGS += --static -nostartfiles +#--specs=nano.specs +LDFLAGS += -L$(LIB_DIR) +LDFLAGS += -T$(LDSCRIPT) +LDFLAGS += -Wl,-Map=$(OBJDIR)/$(BINARY).map +LDFLAGS += -Wl,--gc-sections + +############################################################################### +# Used libraries +LDLIBS += -Wl,--start-group -lc -lgcc -Wl,--end-group +LDLIBS += $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) + +DEFS += -DSTM32$(FAMILY) -DSTM32$(MCU) + +#.SUFFIXES: .elf .bin .hex .srec .list .map .images +#.SECONDEXPANSION: +#.SECONDARY: + +ELF := $(OBJDIR)/$(BINARY).elf +LIST := $(OBJDIR)/$(BINARY).list +BIN := $(BINARY).bin +HEX := $(BINARY).hex + +all: bin list + +elf: $(ELF) +bin: $(BIN) +hex: $(HEX) +list: $(LIST) + +ifneq ($(MAKECMDGOALS),clean) +-include $(DEPS) +endif + +$(OBJDIR): + mkdir $(OBJDIR) + +$(STARTUP): $(INC_DIR)/startup/vector.c + $(CC) $(CFLAGS) $(DEFS) $(INCLUDE) $(ARCH_FLAGS) -o $@ -c $< + +$(OBJDIR)/%.o: %.c + @echo " CC $<" + $(CC) $(CFLAGS) $(DEFS) $(INCLUDE) $(ARCH_FLAGS) -o $@ -c $< + +#$(OBJDIR)/%.d: %.c $(OBJDIR) +# $(CC) -MM -MG $< | sed -e 's,^\([^:]*\)\.o[ ]*:,$(@D)/\1.o $(@D)/\1.d:,' >$@ + +$(BIN): $(ELF) + @echo " OBJCOPY $(BIN)" + $(OBJCOPY) -Obinary $(ELF) $(BIN) + +$(HEX): $(ELF) + @echo " OBJCOPY $(HEX)" + $(OBJCOPY) -Oihex $(ELF) $(HEX) + +$(LIST): $(ELF) + @echo " OBJDUMP $(LIST)" + $(OBJDUMP) -S $(ELF) > $(LIST) + +$(ELF): $(OBJDIR) $(OBJS) + @echo " LD $(ELF)" + $(LD) $(LDFLAGS) $(ARCH_FLAGS) $(OBJS) $(LDLIBS) -o $(ELF) + +clean: + @echo " CLEAN" + $(RM) $(OBJS) $(DEPS) $(ELF) $(HEX) $(LIST) $(OBJDIR)/*.map + @rmdir $(OBJDIR) 2>/dev/null || true + + +flash: $(BIN) + @echo " FLASH $(BIN)" + $(STFLASH) write $(BIN) 0x8000000 + +boot: $(BIN) + @echo " LOAD $(BIN) through bootloader" + $(STBOOT) -b$(BOOTSPEED) $(BOOTPORT) -w $(BIN) + +.PHONY: clean flash boot diff --git a/F0-nolib/tsys01_nucleo/Readme b/F0-nolib/tsys01_nucleo/Readme new file mode 100644 index 0000000..52d5af1 --- /dev/null +++ b/F0-nolib/tsys01_nucleo/Readme @@ -0,0 +1,5 @@ +Example for STM32F042 nucleo working with TSYS-01 temperature sensor. +Every 5 second check temperature on two sensors with different addresses and show values by USART. +USART speed 115200. + + diff --git a/F0-nolib/tsys01_nucleo/i2c.c b/F0-nolib/tsys01_nucleo/i2c.c new file mode 100644 index 0000000..ce25c4b --- /dev/null +++ b/F0-nolib/tsys01_nucleo/i2c.c @@ -0,0 +1,122 @@ +/* + * geany_encoding=koi8-r + * i2c.c + * + * Copyright 2017 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 "stm32f0.h" +#include "i2c.h" + +/** + * I2C for TSYS01 + * Speed <= 400kHz (200) + * t_SCLH > 21ns + * t_SCLL > 21ns + * while reading, sends NACK + * after reading get 24bits of T value, we need upper 2 bytes: ADC16 = ADC>>8 + * T = (-2) * k4 * 10^{-21} * ADC16^4 + * + 4 * k3 * 10^{-16} * ADC16^3 + * + (-2) * k2 * 10^{-11} * ADC16^2 + * + 1 * k1 * 10^{-6} * ADC16 + * +(-1.5)* k0 * 10^{-2} + * All coefficiens are in registers: + * k4 - 0xA2, k3 - 0xA4, k2 - 0xA6, k1 - 0xA8, k0 - 0xAA + */ + +/* + * Resources: I2C1_SCL - PA9, I2C1_SDA - PA10 + * GPIOA->AFR[1] AF4 -- GPIOA->AFR[1] &= ~0xff0, GPIOA->AFR[1] |= 0x440 + */ +extern volatile uint32_t Tms; +static uint32_t cntr; + +void i2c_setup(){ + I2C1->CR1 = 0; + // GPIO + RCC->AHBENR |= RCC_AHBENR_GPIOAEN; // clock + GPIOA->AFR[1] &= ~0xff0; // alternate function F4 for PA9/PA10 + GPIOA->AFR[1] |= 0x440; + GPIOA->OTYPER |= GPIO_OTYPER_OT_9 | GPIO_OTYPER_OT_10; // opendrain + GPIOA->MODER &= ~(GPIO_MODER_MODER9 | GPIO_MODER_MODER10); + GPIOA->MODER |= GPIO_MODER_MODER9_AF | GPIO_MODER_MODER10_AF; // alternate function + // I2C + RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; // timing + RCC->CFGR3 |= RCC_CFGR3_I2C1SW; // use sysclock for timing + // Clock = 6MHz, 0.16(6)us, need 5us (*30) + // PRESC=4 (f/5), SCLDEL=0 (t_SU=5/6us), SDADEL=0 (t_HD=5/6us), SCLL,SCLH=14 (2.(3)us) + I2C1->TIMINGR = (4<<28) | (14<<8) | (14); // 0x40000e0e + I2C1->CR1 = I2C_CR1_PE;// | I2C_CR1_RXIE; // Enable I2C & (interrupt on receive - not supported yet) +} + +/** + * write command byte to I2C + * @param addr - device address (TSYS01_ADDR0 or TSYS01_ADDR1) + * @param data - byte to write + * @return 0 if error + */ +uint8_t write_i2c(uint8_t addr, uint8_t data){ + cntr = Tms; + while(I2C1->ISR & I2C_ISR_BUSY) if(Tms - cntr > 5) return 0; // check busy + cntr = Tms; + while(I2C1->CR2 & I2C_CR2_START) if(Tms - cntr > 5) return 0; // check start + I2C1->CR2 = 1<<16 | addr | I2C_CR2_AUTOEND; // 1 byte, autoend + // now start transfer + I2C1->CR2 |= I2C_CR2_START; + cntr = Tms; + while(!(I2C1->ISR & I2C_ISR_TXIS)){ // ready to transmit + if(I2C1->ISR & I2C_ISR_NACKF){ + I2C1->ICR |= I2C_ICR_NACKCF; + return 0; + } + if(Tms - cntr > 5) return 0; + } + I2C1->TXDR = data; // send data + return 1; +} + +/** + * read nbytes (2 or 3) of data from I2C line + * @return 1 if all OK, 0 if NACK or no device found + */ +uint8_t read_i2c(uint8_t addr, uint32_t *data, uint8_t nbytes){ + uint32_t result = 0; + cntr = Tms; + while(I2C1->ISR & I2C_ISR_BUSY) if(Tms - cntr > 5) return 0; // check busy + cntr = Tms; + while(I2C1->CR2 & I2C_CR2_START) if(Tms - cntr > 5) return 0; // check start + // read N bytes + I2C1->CR2 = (nbytes<<16) | addr | 1 | I2C_CR2_AUTOEND | I2C_CR2_RD_WRN; + I2C1->CR2 |= I2C_CR2_START; + uint8_t i; + cntr = Tms; + for(i = 0; i < nbytes; ++i){ + while(!(I2C1->ISR & I2C_ISR_RXNE)){ // wait for data + if(I2C1->ISR & I2C_ISR_NACKF){ + I2C1->ICR |= I2C_ICR_NACKCF; + return 0; + } + if(Tms - cntr > 5) return 0; + } + result = (result << 8) | I2C1->RXDR; + } + *data = result; + return 1; + } + + diff --git a/F0-nolib/tsys01_nucleo/i2c.h b/F0-nolib/tsys01_nucleo/i2c.h new file mode 100644 index 0000000..496e764 --- /dev/null +++ b/F0-nolib/tsys01_nucleo/i2c.h @@ -0,0 +1,39 @@ +/* + * geany_encoding=koi8-r + * i2c.h + * + * Copyright 2017 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. + * + */ + +// CSB=1, address 1110110 +#define TSYS01_ADDR0 (0x76 << 1) +// CSB=0, address 1110111 +#define TSYS01_ADDR1 (0x77 << 1) +// registers: reset, read ADC value, start converstion, sart of PROM +#define TSYS01_RESET (0x1E) +#define TSYS01_ADC_READ (0x00) +#define TSYS01_START_CONV (0x48) +#define TSYS01_PROM_ADDR0 (0xA0) +// conversion time = 10ms +#define CONV_TIME (10) + +void i2c_setup(); + +uint8_t read_i2c(uint8_t addr, uint32_t *data, uint8_t nbytes); +uint8_t write_i2c(uint8_t addr, uint8_t data); diff --git a/F0-nolib/tsys01_nucleo/ld/stm32f042k.ld b/F0-nolib/tsys01_nucleo/ld/stm32f042k.ld new file mode 100644 index 0000000..e747253 --- /dev/null +++ b/F0-nolib/tsys01_nucleo/ld/stm32f042k.ld @@ -0,0 +1,12 @@ +/* Linker script for STM32F042x6, 32K flash, 6K RAM. */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 32K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 6K +} + +/* Include the common ld script. */ +INCLUDE stm32f0.ld + diff --git a/F0-nolib/tsys01_nucleo/main.c b/F0-nolib/tsys01_nucleo/main.c new file mode 100644 index 0000000..0a511e0 --- /dev/null +++ b/F0-nolib/tsys01_nucleo/main.c @@ -0,0 +1,151 @@ +/* + * main.c + * + * Copyright 2017 Edward V. Emelianoff + * + * 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 "stm32f0.h" +#include "usart.h" +#include "i2c.h" + +volatile uint32_t Tms = 0; + +/* Called when systick fires */ +void sys_tick_handler(void){ + ++Tms; +} + +static void gpio_setup(void){ + // Set green led (PB3) as output + RCC->AHBENR |= RCC_AHBENR_GPIOBEN; + GPIOB->MODER = GPIO_MODER_MODER3_O; +} + +// print 32bit unsigned int +void printu(uint32_t val){ + char buf[11], rbuf[10]; + int l = 0, bpos = 0; + if(!val){ + buf[0] = '0'; + l = 1; + }else{ + while(val){ + rbuf[l++] = val % 10 + '0'; + val /= 10; + } + int i; + bpos += l; + for(i = 0; i < l; ++i){ + buf[--bpos] = rbuf[i]; + } + } + while(ALL_OK != usart2_send_blocking(buf, l+bpos)); +} + +void showcoeffs(uint8_t addr){ // show norm coefficiens + int i; + const uint8_t regs[5] = {0xAA, 0xA8, 0xA6, 0xA4, 0xA2}; // commands for coefficients + uint32_t K; + for(i = 0; i < 5; ++i){ + if(write_i2c(addr, regs[i])){ + if(read_i2c(addr, &K, 2)){ + char b[3] = {'K', i+'0', '='}; + while(ALL_OK != usart2_send_blocking(b, 3)); + printu(K); + while(ALL_OK != usart2_send_blocking("\n", 1)); + } + } + } +} + +int main(void){ + uint32_t lastT = 0; + int16_t L = 0; + int _5sec = 0; // five second counter + uint32_t started0=0, started1=0; // time of measurements for given sensor started + uint32_t msctr = 0; + char *txt; + sysreset(); + SysTick_Config(6000, 1); + gpio_setup(); + usart2_setup(); + i2c_setup(); + // reset on start + write_i2c(TSYS01_ADDR0, TSYS01_RESET); + write_i2c(TSYS01_ADDR1, TSYS01_RESET); + + while (1){ + if(lastT > Tms || Tms - lastT > 499){ + pin_toggle(GPIOB, 1<<3); // blink by onboard LED once per second + lastT = Tms; + } + if(started0 && Tms - started0 > CONV_TIME){ // poll sensor0 + if(write_i2c(TSYS01_ADDR0, TSYS01_ADC_READ)){ + uint32_t t; + if(read_i2c(TSYS01_ADDR0, &t, 3)){ + while(ALL_OK != usart2_send_blocking("T0=", 3)); + printu(t); + while(ALL_OK != usart2_send_blocking("\n", 1)); + started0 = 0; + } + } + } + if(started1 && Tms - started1 > CONV_TIME){ // poll sensor1 + if(write_i2c(TSYS01_ADDR1, TSYS01_ADC_READ)){ + uint32_t t; + if(read_i2c(TSYS01_ADDR1, &t, 3)){ + while(ALL_OK != usart2_send_blocking("T1=", 3)); + printu(t); + while(ALL_OK != usart2_send_blocking("\n", 1)); + started1 = 0; + } + } + } + if(usart2rx()){ // usart1 received data, store in in buffer + L = usart2_getline(&txt); + if(L == 2){ + if(txt[0] == 'C'){ // 'C' - show coefficients + showcoeffs(TSYS01_ADDR0); + showcoeffs(TSYS01_ADDR1); + }else if(txt[0] == 'R'){ // 'R' - reset both + write_i2c(TSYS01_ADDR0, TSYS01_RESET); + write_i2c(TSYS01_ADDR1, TSYS01_RESET); + }else if(txt[0] == 'I'){ // 'I' - reinit I2C + i2c_setup(); + } + } + } + if(L){ // text waits for sending + if(ALL_OK == usart2_send(txt, L)){ + L = 0; + } + } + if(msctr != Tms){ + msctr = Tms; + if(++_5sec >= 5000){ // once per 5 second + _5sec = 0; + if(write_i2c(TSYS01_ADDR0, TSYS01_START_CONV)) started0 = Tms; + else started0 = 0; + if(write_i2c(TSYS01_ADDR1, TSYS01_START_CONV)) started1 = Tms; + else started1 = 0; + } + } + } + return 0; +} + diff --git a/F0-nolib/tsys01_nucleo/tsys01.bin b/F0-nolib/tsys01_nucleo/tsys01.bin new file mode 100755 index 0000000000000000000000000000000000000000..3c7a8672091718b0d4cf860a4bb79b01815f1cb8 GIT binary patch literal 2784 zcma)8YitzP6+U-nyx2T>zq)b;G`+(Bv~(B~r(}7D)x66~O%9Dl{z_#YfHKP)FKZVP~y3 z229nM_cQlUbr7jV+oqP25BejK0H>mrXly}SEDMJ@1XXR z91|ih+q3`T>|$dbTozxbx0-cO`6+utXy+@g7LKo=IVoX%P@u$w1pg+N}OibwK zhM!W-4GJTpwtfgglX_z0fRY&cQJiZlNB?I!6Zo{ni*cqy57AN9t0eSvC_sB$c8+vt z)D@uR^7R}WOi=ViTe9A^*&X+`^-^Ed6TW85h~MpeLVKc1)1_f>S20yyR*?ol%IIvw zr>CWD$$7@7^bS0(LBpgPm3mZO2ebJqnEzg^4PFotFVzM=#<6}0Br-Okj;p&gsE5WW zb)-w8&&x$~pM)f8t(~tLlYM7<)pRhCEMa*U<`4c@=}~>k*gzvyR0x;nWL2V5f;U`x z7M$4E7NNDyt0*EnT_zP0MX_535xa!s`uK(`rDyM9Ji&d?JVAJ!DMN zo|E4^A9G@zSp;cZg(iY)<7&*|d#KQh4FvB-=!!#@h( zWP28~z3A-5eqVO(X*`>H%&_DCId@@B5j9`AnR7yYrT~)7ufK3Xw5}Yu@i9L4-C)L< z;2VYI6QFn!cEqn?HYWIMybr)J(bC^p9?SadhGku|ENjMEjR-_0YJKm7#Vx?XBX?rQ zxCjg2f|wugr+r8F@c=ojTf27uf&!Ailgrw5aA$mq=}uO5u~-WSrTL=%VKLf2__Vlv zcm_nJe{e?JP93EC>B=rK>er{mYMN$6#gE>(t=Bx~dnV>yCnZcnmW{xtXGAQ9Px*<_9K_5g?}u0akGoktGQx!03+u5?2q4Q}}@a#+^4&yCOs>UkHd zRLA@Z)kkQp0@AniMtTTu1hfdbJ7TVSuEAzhEBlRQKR+_6K}L#N#f+<)RAo4z45=hC zf9z@XkUA+}G88qg5|P(k3tVV6$t$zSxD-3ggwtbg@g^={JlJm`Tx=A_D=4EE$9cV2 z^V8I3ka(Sq1IAb^cyOQ7DE4`;LRlH-vZYW?i3H6|jzprX$$39;$MGfuuX|!40P}$* zBD%EzeNqYN+p$wI*jqsQsDRZY9zp2cLrB6b2K+(V_}cQNk#rVq#F##Q3Bx#?LtnXGB4-)xa%0RKZku(R*7u^sZ>t zRS@ipAoTx25xUdTACglHubdjlNzve{_`{IbgBz?3WBOwoczu~MkLOW7Ch3$kx4} zL~26Olm3f-Xer8p^vCTN`bcC9*UaNZ@L55C|Jc1ZqoW8ZxY}%QF}IVSWi}gWU)3(_abB8@8&DH#|x>=cAfRLZiK$Jjo`(iCn)~|cHn8C literal 0 HcmV?d00001 diff --git a/F0-nolib/tsys01_nucleo/usart.c b/F0-nolib/tsys01_nucleo/usart.c new file mode 100644 index 0000000..876b113 --- /dev/null +++ b/F0-nolib/tsys01_nucleo/usart.c @@ -0,0 +1,152 @@ +/*us + * usart.c + * + * Copyright 2017 Edward V. Emelianoff + * + * 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 "stm32f0.h" +#include "usart.h" +#include + +extern volatile uint32_t Tms; +static int datalen[2] = {0,0}; // received data line length (including '\n') + +int linerdy = 0, // received data ready + dlen = 0, // length of data (including '\n') in current buffer + bufovr = 0, // input buffer overfull + txrdy = 1 // transmission done +; + + +int rbufno = 0; // current rbuf number +static char rbuf[UARTBUFSZ][2], tbuf[UARTBUFSZ]; // receive & transmit buffers +static char *recvdata = NULL; + +/** + * return length of received data (without trailing zero + */ +int usart2_getline(char **line){ + if(bufovr){ + bufovr = 0; + linerdy = 0; + return 0; + } + *line = recvdata; + linerdy = 0; + return dlen; +} + +TXstatus usart2_send(const char *str, int len){ + if(!txrdy) return LINE_BUSY; + if(len > UARTBUFSZ) return STR_TOO_LONG; + txrdy = 0; + memcpy(tbuf, str, len); + DMA1_Channel4->CCR &= ~DMA_CCR_EN; + DMA1_Channel4->CNDTR = len; + DMA1_Channel4->CCR |= DMA_CCR_EN; // start transmission + return ALL_OK; +} + +TXstatus usart2_send_blocking(const char *str, int len){ + if(!txrdy) return LINE_BUSY; + int i; + bufovr = 0; + for(i = 0; i < len; ++i){ + USART2->TDR = *str++; + while(!(USART2->ISR & USART_ISR_TXE)); + } + txrdy = 1; + return ALL_OK; +} + + +// Nucleo's USART2 connected to VCP proxy of st-link +void usart2_setup(){ + // setup pins: PA2 (Tx - AF1), PA15 (Rx - AF1) + RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_DMAEN; + // AF mode (AF1) + GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODER2|GPIO_MODER_MODER15))\ + | (GPIO_MODER_MODER2_1 | GPIO_MODER_MODER15_1); + GPIOA->AFR[0] = (GPIOA->AFR[0] &~GPIO_AFRH_AFRH2) | 1 << (2 * 4); // PA2 + GPIOA->AFR[1] = (GPIOA->AFR[1] &~GPIO_AFRH_AFRH7) | 1 << (7 * 4); // PA15 + // DMA: Tx - Ch4 + DMA1_Channel4->CPAR = (uint32_t) &USART2->TDR; // periph + DMA1_Channel4->CMAR = (uint32_t) tbuf; // mem + DMA1_Channel4->CCR |= DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TCIE; // 8bit, mem++, mem->per, transcompl irq + // Tx CNDTR set @ each transmission due to data size + NVIC_SetPriority(DMA1_Channel4_5_IRQn, 3); + NVIC_EnableIRQ(DMA1_Channel4_5_IRQn); + NVIC_SetPriority(USART2_IRQn, 0); + // setup usart2 + RCC->APB1ENR |= RCC_APB1ENR_USART2EN; // clock + // oversampling by16, 115200bps (fck=48mHz) + //USART2_BRR = 0x1a1; // 48000000 / 115200 + USART2->BRR = 480000 / 1152; + USART2->CR3 = USART_CR3_DMAT; // enable DMA Tx + USART2->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; // 1start,8data,nstop; enable Rx,Tx,USART + while(!(USART2->ISR & USART_ISR_TC)); // polling idle frame Transmission + USART2->ICR |= USART_ICR_TCCF; // clear TC flag + USART2->CR1 |= USART_CR1_RXNEIE; + NVIC_EnableIRQ(USART2_IRQn); +} + + +void dma1_channel4_5_isr(){ + if(DMA1->ISR & DMA_ISR_TCIF4){ // Tx + DMA1->IFCR |= DMA_IFCR_CTCIF4; // clear TC flag + txrdy = 1; + } +} + +void usart2_isr(){ + #ifdef CHECK_TMOUT + static uint32_t tmout = 0; + #endif + if(USART2->ISR & USART_ISR_RXNE){ // RX not emty - receive next char + #ifdef CHECK_TMOUT + if(tmout && Tms >= tmout){ // set overflow flag + bufovr = 1; + datalen[rbufno] = 0; + } + tmout = Tms + TIMEOUT_MS; + if(!tmout) tmout = 1; // prevent 0 + #endif + // read RDR clears flag + uint8_t rb = USART2->RDR; + if(datalen[rbufno] < UARTBUFSZ){ // put next char into buf + rbuf[rbufno][datalen[rbufno]++] = rb; + if(rb == '\n'){ // got newline - line ready + linerdy = 1; + dlen = datalen[rbufno]; + recvdata = rbuf[rbufno]; + // prepare other buffer + rbufno = !rbufno; + datalen[rbufno] = 0; + #ifdef CHECK_TMOUT + // clear timeout at line end + tmout = 0; + #endif + } + }else{ // buffer overrun + bufovr = 1; + datalen[rbufno] = 0; + #ifdef CHECK_TMOUT + tmout = 0; + #endif + } + } +} diff --git a/F0-nolib/tsys01_nucleo/usart.h b/F0-nolib/tsys01_nucleo/usart.h new file mode 100644 index 0000000..34a1388 --- /dev/null +++ b/F0-nolib/tsys01_nucleo/usart.h @@ -0,0 +1,48 @@ +/* + * usart.h + * + * Copyright 2017 Edward V. Emelianoff + * + * 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 __USART_H__ +#define __USART_H__ + +// input and output buffers size +#define UARTBUFSZ (64) +// timeout between data bytes +#ifndef TIMEOUT_MS +#define TIMEOUT_MS (1500) +#endif + +typedef enum{ + ALL_OK, + LINE_BUSY, + STR_TOO_LONG +} TXstatus; + +#define usart2rx() (linerdy) +#define usart2ovr() (bufovr) + +extern int linerdy, bufovr, txrdy; + +void usart2_setup(); +int usart2_getline(char **line); +TXstatus usart2_send(const char *str, int len); +TXstatus usart2_send_blocking(const char *str, int len); + +#endif // __USART_H__