From 54a9e365ff2d8f4d138bc855fb9f07196dc640e9 Mon Sep 17 00:00:00 2001 From: eddyem Date: Wed, 1 Mar 2017 21:58:33 +0300 Subject: [PATCH] Add HTU-21d for NUCLEO --- F0-nolib/Readme.md | 4 +- F0-nolib/htu21d_nucleo/Makefile | 137 ++++++++++++++ F0-nolib/htu21d_nucleo/Readme | 5 + F0-nolib/htu21d_nucleo/i2c.c | 237 ++++++++++++++++++++++++ F0-nolib/htu21d_nucleo/i2c.h | 44 +++++ F0-nolib/htu21d_nucleo/ld/stm32f042k.ld | 12 ++ F0-nolib/htu21d_nucleo/main.c | 124 +++++++++++++ F0-nolib/htu21d_nucleo/usart.bin | Bin 0 -> 2888 bytes F0-nolib/htu21d_nucleo/usart.c | 152 +++++++++++++++ F0-nolib/htu21d_nucleo/usart.h | 48 +++++ 10 files changed, 762 insertions(+), 1 deletion(-) create mode 100644 F0-nolib/htu21d_nucleo/Makefile create mode 100644 F0-nolib/htu21d_nucleo/Readme create mode 100644 F0-nolib/htu21d_nucleo/i2c.c create mode 100644 F0-nolib/htu21d_nucleo/i2c.h create mode 100644 F0-nolib/htu21d_nucleo/ld/stm32f042k.ld create mode 100644 F0-nolib/htu21d_nucleo/main.c create mode 100755 F0-nolib/htu21d_nucleo/usart.bin create mode 100644 F0-nolib/htu21d_nucleo/usart.c create mode 100644 F0-nolib/htu21d_nucleo/usart.h diff --git a/F0-nolib/Readme.md b/F0-nolib/Readme.md index 7e575fd..2d74344 100644 --- a/F0-nolib/Readme.md +++ b/F0-nolib/Readme.md @@ -4,6 +4,8 @@ Samples for STM32F042-nucleo and chinese STM32F030-based devboard 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 - 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 -- morze - for STM32F030, echo data from USART1 on TIM3CH1 (PA6) as Morze code +- uart_nucleo - USART over DMA for STM32F042-nucleo diff --git a/F0-nolib/htu21d_nucleo/Makefile b/F0-nolib/htu21d_nucleo/Makefile new file mode 100644 index 0000000..48a5249 --- /dev/null +++ b/F0-nolib/htu21d_nucleo/Makefile @@ -0,0 +1,137 @@ +BINARY = usart +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/htu21d_nucleo/Readme b/F0-nolib/htu21d_nucleo/Readme new file mode 100644 index 0000000..6ead455 --- /dev/null +++ b/F0-nolib/htu21d_nucleo/Readme @@ -0,0 +1,5 @@ +Example for STM32F042 nucleo working with HTU-21D humidity/temperature sensor. +Every 1 second check humidity/temperature and show values by USART. +USART speed 115200. + + diff --git a/F0-nolib/htu21d_nucleo/i2c.c b/F0-nolib/htu21d_nucleo/i2c.c new file mode 100644 index 0000000..329b044 --- /dev/null +++ b/F0-nolib/htu21d_nucleo/i2c.c @@ -0,0 +1,237 @@ +/* + * 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 HTU21D + * Speed <= 400kHz (200) + * t_SCLH ~ 0.6us + * t_SCLL ~ 1.3us + * t_SU >= 100ns + * t_HD <= 900ns + * t_VD <= 400ns + * + * After start 15ms pause for IDLE + * Start bit: SCK=1, DATA 1->0 + * Stop bit: SCK 0->1, DATA 0->1 + * Address: 0x40 (7bit), 0th bit - direction (0 - write, 1 - read) + * ACK: DATA->0 on 8th SCK clock + * Commands: 0xE3[F3] - temperature, 0xE5[F5] - humidity [No hold master] + * 0xE6 - write user register, 0xE7 - read user register, 0xFE - soft reset + * 7 6 5 4 3 2 1 0 + * User register: |D1|Vbat|reserved|Htr|Odis|D0| default: 0x02 + * D1D0 - resolution [H/T]: 00-12/14, 01-8/12, 10-10/13, 11-11/11 + * Vbat=1 vhen Vdd<2.25V, Htr=1 to enable on-chip heater, + * Odis=0 to enable OTP reload (after each measurement reload defaults) + * + * in = in & 0xFFFC; + * Calculations: RH = -6 + 125*Hum/2^16 + * T = -46.85 + 175.72*Temp/2^16 + */ + +/* + * 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(){ + // 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) +} +// I2C2->TIMINGR = (uint32_t)0x00B01A4B; +// PRECS=0 - tpresc=20.8(3)ns, SCLDEL=B (tSU 12tpresc), SDADEL=0 (tHD=0), SCLH=1a (27), SCLL=4B (76) +// https://github.com/mattbrejza/magnet-node/blob/master/firmware-basestation/htu21.c +// prescaler = 1, low period = 0x13, high period = 0xf, hold time = 2, setup = 4 +// I2C_TIMINGR(H_I2C) = (1<<28) | (4<<20) | (2<<16) | (0xf<<8) | 0x13; + +/* transmit: + * I2Cx_CR2: + * Addressing mode (7-bit or 10-bit): ADD10 + * Slave address to be sent: SADD[9:0] + * Transfer direction: I2C_CR2_RD_WRN=0 + * The number of bytes to be transferred: NBYTES[7:0] (NBYTES<<16) + * You must then set the START bit in I2Cx_CR2 register. + * Automatic end mode (AUTOEND = '1' in the I2Cx_CR2 register), + * I2C1->CR2 = I2C_CR2_HEAD10R | SLAVE_ADDR; // 7bit, slave address + */ +// return 1 if all OK, 0 if NACK +uint8_t htu_write_i2c(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 | HTU21_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; +} + +#define SHIFTED_DIVISOR 0x988000 //This is the 0x0131 polynomial shifted to farthest left of three bytes +// check CRC, return 0 if all OK +uint32_t htu_check_crc(uint16_t data, uint8_t crc){ + uint32_t remainder = (uint32_t)data << 8; + remainder |= crc; + uint32_t divsor = (uint32_t)SHIFTED_DIVISOR; + int i; + for(i = 0; i < 16; i++) { + if (remainder & (uint32_t)1 << (23 - i)) + remainder ^= divsor; + divsor >>= 1; + } + return remainder; +} + +// return 1 if all OK, 0 if NACK +uint8_t htu_read_i2c(uint16_t *data){ + uint8_t buf[3]; + 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 three bytes + I2C1->CR2 = 3<<16 | HTU21_ADDR | 1 | I2C_CR2_AUTOEND | I2C_CR2_RD_WRN; + I2C1->CR2 |= I2C_CR2_START; + int i; + cntr = Tms; + for(i = 0; i < 3; ++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; + } + buf[i] = I2C1->RXDR; + } + *data = (buf[0] << 8) | buf[1]; + if(htu_check_crc(*data, buf[2])) return 1; // CRC error + return 1; + } + +// return 0 if all OK +uint8_t htu_read_reg(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 | HTU21_ADDR; // 1 byte + 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 = HTU21_READ_REG; + cntr = Tms; + while(!(I2C1->ISR & I2C_ISR_TC)) if(Tms - cntr > 5) return 0; // wait transfer completion + I2C1->CR2 = 1<<16 | HTU21_ADDR | 1 | I2C_CR2_RD_WRN | I2C_CR2_AUTOEND; // receive, autoend + I2C1->CR2 |= I2C_CR2_START; + cntr = Tms; + 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; + } + *data = I2C1->RXDR; + return 1; +} + +uint8_t htu_write_reg(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 | HTU21_ADDR; // 1 byte + 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 = HTU21_WRITE_REG; + cntr = Tms; + while(!(I2C1->ISR & I2C_ISR_TC)) if(Tms - cntr > 5) return 0; // wait transfer completion + I2C1->CR2 |= I2C_CR2_AUTOEND; // receive, autoend + 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; + return 1; +} + + +//output in Cx10 +int16_t convert_temperature(uint16_t in){ + in = in & 0xFFFC; + uint32_t a = (uint32_t)in * 17572; + a >>= 16; + int16_t val = ((int16_t)a - 4685)/10; + return val; +} + +//output in %x10 +int16_t convert_humidity(uint16_t in){ + in = in & 0xFFFC; + uint32_t a = (uint32_t)in * 1250; + a >>= 16; + int16_t val = (int16_t)a - 60; + return val; +} diff --git a/F0-nolib/htu21d_nucleo/i2c.h b/F0-nolib/htu21d_nucleo/i2c.h new file mode 100644 index 0000000..5e772fe --- /dev/null +++ b/F0-nolib/htu21d_nucleo/i2c.h @@ -0,0 +1,44 @@ +/* + * 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. + * + */ + +#define HTU21_ADDR (0x40 << 1) +#define HTU21_READ_TEMP (0xF3) +#define HTU21_READ_HUMID (0xF5) +#define HTU21_READ_REG (0xE7) +#define HTU21_WRITE_REG (0xE6) +#define HTU21_SOFT_RESET (0xFE) +// user reg fields +#define HTU21_REG_VBAT (0x40) +#define HTU21_REG_D1 (0x80) +#define HTU21_REG_D0 (0x01) +#define HTU21_REG_HTR (0x04) +#define HTU21_REG_ODIS (0x02) + +void i2c_setup(); + +int16_t convert_temperature(uint16_t in); +int16_t convert_humidity(uint16_t in); +uint8_t htu_write_reg(uint8_t data); +uint8_t htu_read_reg(uint8_t *data); +uint8_t htu_read_i2c(uint16_t *data); +uint8_t htu_write_i2c(uint8_t data); diff --git a/F0-nolib/htu21d_nucleo/ld/stm32f042k.ld b/F0-nolib/htu21d_nucleo/ld/stm32f042k.ld new file mode 100644 index 0000000..e747253 --- /dev/null +++ b/F0-nolib/htu21d_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/htu21d_nucleo/main.c b/F0-nolib/htu21d_nucleo/main.c new file mode 100644 index 0000000..ad955e5 --- /dev/null +++ b/F0-nolib/htu21d_nucleo/main.c @@ -0,0 +1,124 @@ +/* + * 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; +} + +void printi(int16_t val){ + char buf[6], rbuf[5]; + int l = 0, bpos = 0; + if(!val){ + buf[0] = '0'; + l = 1; + }else{ + if(val < 0){ + buf[0] = '-'; + bpos = 1; + val = -val; + } + 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)); +} + +int main(void){ + uint32_t lastT = 0; + int16_t L = 0; + int _1sec = 0, T_H = 0; // T_H - read t(1) or h(0) + uint32_t msctr = 0; + char *txt; + sysreset(); + SysTick_Config(6000, 1); + gpio_setup(); + usart2_setup(); + i2c_setup(); + + while (1){ + if(lastT > Tms || Tms - lastT > 499){ + pin_toggle(GPIOB, 1<<3); // blink by onboard LED once per second + lastT = Tms; + } + if(usart2rx()){ // usart1 received data, store in in buffer + L = usart2_getline(&txt); + printi(L); + // do something with received data + } + if(L){ // text waits for sending + if(ALL_OK == usart2_send(txt, L)){ + L = 0; + } + } + if(msctr != Tms){ + msctr = Tms; + if(++_1sec >= 1000){ // once per 1 second + _1sec = 0; + // send H/T + uint8_t command = HTU21_READ_HUMID; + if(T_H) command = HTU21_READ_TEMP; + if(!htu_write_i2c(command)) + while(ALL_OK != usart2_send_blocking("Error!\n", 7)); + } + } + // poll I2C + uint16_t val = 0; + if(htu_read_i2c(&val)){ // got data + if(T_H){ + while(ALL_OK != usart2_send_blocking("Temperature: ", 13)); + int16_t t = convert_temperature(val); + printi(t); + while(ALL_OK != usart2_send_blocking("/10 degrC\n", 10)); + }else{ + while(ALL_OK != usart2_send_blocking("Humidity: ", 10)); + int16_t h = convert_humidity(val); + printi(h); + while(ALL_OK != usart2_send_blocking("/10 %\n", 6)); + } + T_H = !T_H; + }else{ + if(val) // CRC error + while(ALL_OK != usart2_send_blocking("CRC error!\n", 11)); + } + } + return 0; +} + diff --git a/F0-nolib/htu21d_nucleo/usart.bin b/F0-nolib/htu21d_nucleo/usart.bin new file mode 100755 index 0000000000000000000000000000000000000000..9f990b1b7de96564034d12c461f07586862d9486 GIT binary patch literal 2888 zcmb_ee{2)?6@TA5JMoW%Tzrt(M}Rw@DIpFcS)c_njpHsHjt>wdpe7DeFM*765NeiE zX>>no=r4jh4aL$H5>`+_Tcvds%4TVr7AY+f6V0mn;-Ll@n>S6ev=!AFqa?t%y}N{| z>m<}a7U|{t@%z3XpYQkk-m@VH{IzoMTtzWa;4y!;&7*A_zYFs|w%-?#^!Ry7r_|B} z)Co6098sxvU=*|4djq8DH92!0`74=_15c`*p2b1cReWba1 zfNVM|&zcQj7S}jATIGh8$oPmlQ=C+ZP|E&MeOleAZdG5^3R%v0HRe+|Jz>0dk&+TR zXS@`nBo5c(&YCce;abHf^y~e{mFvCSq3_xH{SY426NgSJiT&S>Gfma#|3X^=|J&lj zIOoD$#xU(u5_&2eGTL2sj#PNq6*8*j2RT|u80d?(WTS0!Ant4GF#M7ydf%Mnjkctg z+^*?jKa?${milN#>;*Bc)6IT8CGJk%p!`ZlPp>wrN@Bap>QLhDK`A#2B9$ST5fw6Y zrd!*$V@!4Z>}+kf*1i3-+PyPs(5Fw!?wNmvqlWdBZZ0ENT~iX4a=pd|&Rxml=Nl_MDC%ehJ+rb6k>Is2tIoPg5iIqUA7hd$xS7{0%wB_bJ3 zNM!h}V!6O$RlM$KotO*pOpN!D*>VD+Kg{_ByK-J|Y<^Jm2`e$qbN`7R!RVJCmI(rC zjsJ>%v={>S2$VLWHe;SDy5E9QXpSBa0%WYaZ$Eq)>jW4|s`!=Vv8+!YTGoBbvL>wt zM8H#$_2PRLQ-H#=U&4;N1qEOCQJ_Fn;_boEXOorZ(-kWm>UQb<211dSn@C?R}#GdV{46-LPSu!sB# zyWg#q#kn35=CH$TzEvfpXltXFLg)jX3i)5*d3|J z5`%5KKpyF9XEZ}ZeU-+n)O5|LRkrIjhQE!9lois+WwO^~jWP81%%qdG@}1m?Uc%Fb zspK-{gC5`qChW7@c~d|ryU$YsWFzt87gOpIL)`AA9_88inf%K>lYh-Z{*VT%?EK8i zc?OHyTnh|>3k-q_47C0;>LFEEUClFl$y4;&+vXvaJKB9TK(UIf5}r-D3QTw^$tqLG zkXo25k9Zz)(G)F?C^VGCm~5xw)}Z2y>J#)<56(A;mYe1AfI;cyaaJ$af(E{Y$m(<)cvhb+dhlM(q1g4Y7-dnM$yPwM zK}1+hLeK?6IoE;$ky@=JuUqEREN@~nj z?jT~l0ri0#g#B7;5N%d_Z>9uqocW18JlC7(m)rpo@KVY!pXlW^K0d1R z@#_x5NuJY}Yf#2@1*m`zy?3X=zvZn+fZ*H%uJcWW+m#aEPmba1O!eeMNmv~3hP*Dc zSS=a-xfWKRXUz78l_fyUu`E7Ds*RBB&h5q+9Xbh9n%yDx*(nLoc8ONXUQZ5}RbO4aV{u!(G4}c?Xzd&u z-`wE+!#8TxT}30GnS5S3lCMH2CAwYpzhjuO;6-Ayi z*!8!fo&OBRuRy6qvG4iOyPre+5a)``qb|O>?W9~WeN{Oeq=oM*)$oMoTK{p7Op$lb z%lFOpkcj)0({vNN>+q8M}DF-FAGaog13TD@5b+x-|hQ&4{6TeUTMM&pB6dz z2i_^I`jr=d4`IcVmXG9VZ(4pPPy5nxYo7L}<+?mwk(Mj-R@h4ger;naAHX8+%h|i3 zJQTdXONdB*ik{@!x4h)ww1X7~YYw)pN#5_^OBfyPDaYQyX$LC~)*NgzKzj#&FntMG zp$Bn19GrHr;$Y3eHgoiF@FhG8+Jj^7;IxD7Gm^aK;4K_X6SaK{gH`qQ!uwT_Ym;dP z@{-&kLHLYn$6MpvL?HhlJVfyH$f+VfM24%=vS(p+;kqd|Tn&XG@BfSCwdw!mxgVK! zGmJ`*AO2pr+9nTd+pl&zd`T9oyX2mwCSdh!uBJG!&F+(}gM-fw3O?A=cX*(0u;Aol#> + * + * 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/htu21d_nucleo/usart.h b/F0-nolib/htu21d_nucleo/usart.h new file mode 100644 index 0000000..34a1388 --- /dev/null +++ b/F0-nolib/htu21d_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__