diff --git a/F3:F303/BME280/BMP280.c b/F3:F303/BME280/BMP280.c index a1bd6ba..bad50a7 100644 --- a/F3:F303/BME280/BMP280.c +++ b/F3:F303/BME280/BMP280.c @@ -42,16 +42,18 @@ * along with this program. If not, see . */ +#include "hardware.h" #include "i2c.h" #include "spi.h" #include "BMP280.h" +#include "usb_dev.h" // DBG #ifdef EBUG #include "strfunc.h" -#include "usb_dev.h" extern volatile uint32_t Tms; #endif +#include #include #define BMP280_I2C_ADDRESS_MASK (0x76) @@ -87,6 +89,8 @@ extern volatile uint32_t Tms; #define BMP280_MODE_FORSED (1) // force single measurement #define BMP280_MODE_NORMAL (3) // run continuosly +#define BMP280_STATUS_IMCOPY (1<<0) // im-copy (sensor busy) +#define BME280_STATUS_MSRGOOD (1<<2) // measurement is good (undocumented bit) #define BMP280_STATUS_MSRNG (1<<3) // measuring in process static uint8_t curaddress = BMP280_I2C_ADDRESS_0<<1; @@ -165,17 +169,27 @@ BMP280_status BMP280_get_status(){ static uint8_t SPIbuf[SPI_BUFSIZE]; // these functions for -static uint8_t *spi_readregs(uint8_t address, uint8_t reg, uint8_t len){ +static uint8_t *spi_readregs(uint8_t _U_ address, uint8_t reg, uint8_t len){ if(len > SPI_BUFSIZE-2) return NULL; - SPIbuf[0] = address | 0x80; - SPIbuf[1] = reg; - if(!spi_writeread(SPIbuf, len+2)) return NULL; - return SPIbuf + 2; + SPI_CS_0(); + bzero(SPIbuf, sizeof(SPIbuf)); + SPIbuf[0] = reg | 0x80; + int r = spi_writeread(SPIbuf, len+1); + SPI_CS_1(); + if(!r) return NULL; +#ifdef EBUG + USB_sendstr("Register "); USB_sendstr(uhex2str(reg)); USB_sendstr(": "); + hexdump(USB_sendstr, SPIbuf + 1, len); +#endif + return SPIbuf + 1; } -static uint8_t spi_write(uint8_t address, uint8_t *data, uint8_t n){ - SPIbuf[0] = address; - memcpy(SPIbuf + 1, data, n); - return spi_writeread(SPIbuf, n+1); +static uint8_t spi_write(uint8_t _U_ address, uint8_t *data, uint8_t n){ + SPI_CS_0(); + memcpy(SPIbuf, data, n); + SPIbuf[0] &= 0x7F; // clear MSbit + uint8_t r = spi_writeread(SPIbuf, n); + SPI_CS_1(); + return r; } // address: 0 or 1 @@ -185,14 +199,13 @@ void BMP280_setup(uint8_t address, uint8_t isI2C){ curaddress = (BMP280_I2C_ADDRESS_MASK | (address & 1))<<1; read_regs = i2c_read_regs; write_data = i2c_write; - i2c_setup(I2C_SPEED_10K); + i2c_setup(I2C_SPEED_400K); }else{ curaddress = BMP280_I2C_ADDRESS_MASK | (address & 1); read_regs = spi_readregs; write_data = spi_write; spi_setup(); } - BMP280_init(); } // setters for `params` @@ -233,43 +246,49 @@ static int readcompdata(){ // read compensation data & write registers int BMP280_init(){ IWDG->KR = IWDG_REFRESH; - DBG("INI:\n"); + DBG("INI:"); if(!read_reg(BMP280_REG_ID, ¶ms.ID)){ - DBG("Can't get ID\n"); + DBG("Can't get ID"); return 0; } if(params.ID != BMP280_CHIP_ID && params.ID != BME280_CHIP_ID){ - DBG("Not BMP/BME\n"); + DBG("Not BMP/BME"); return 0; } if(!write_reg(BMP280_REG_RESET, BMP280_RESET_VALUE)){ - DBG("Can't reset\n"); + DBG("Can't reset"); return 0; } uint8_t reg = 1; - while(reg & 1){ + int ntries = 100; + while((reg & BMP280_STATUS_IMCOPY) && --ntries){ + IWDG->KR = IWDG_REFRESH; if(!read_reg(BMP280_REG_STATUS, ®)){ - DBG("can't get status\n"); + DBG("can't get status"); return 0; } } + if(ntries < 0){ + DBG("Timeout getting status"); + return 0; + } if(!readcompdata()){ - DBG("Can't read calibration data\n"); + DBG("Can't read calibration data"); return 0; } // write filter configuration reg = params.filter << 2; - if(!write_reg(BMP280_REG_CONFIG, reg)){DBG("Can't save filter settings\n");} + if(!write_reg(BMP280_REG_CONFIG, reg)){DBG("Can't save filter settings");} reg = (params.t_os << 5) | (params.p_os << 2); // oversampling for P/T, sleep mode if(!write_reg(BMP280_REG_CTRL, reg)){ - DBG("Can't write settings for P/T\n"); + DBG("Can't write settings for P/T"); return 0; } params.regctl = reg; if(params.ID == BME280_CHIP_ID){ // write CTRL_HUM only AFTER CTRL! reg = params.h_os; if(!write_reg(BMP280_REG_CTRL_HUM, reg)){ - DBG("Can't write settings for H\n"); + DBG("Can't write settings for H"); return 0; } } @@ -296,7 +315,7 @@ int BMP280_start(){ } uint8_t reg = params.regctl | BMP280_MODE_FORSED; if(!write_reg(BMP280_REG_CTRL, reg)){ - DBG("Can't write CTRL reg\n"); + DBG("Can't write CTRL reg"); return 0; } bmpstatus = BMP280_BUSY; @@ -311,7 +330,13 @@ void BMP280_process(){ // BUSY state: poll data ready uint8_t reg; if(!read_reg(BMP280_REG_STATUS, ®)) return; - if(reg & BMP280_STATUS_MSRNG) return; // still busy + if(reg & (BMP280_STATUS_MSRNG | BMP280_STATUS_IMCOPY)) return; // still busy + /* if(params.ID == BME280_CHIP_ID && !(reg & BME280_STATUS_MSRGOOD)){ // check if data is good + DBG("Wrong data!"); + bmpstatus = BMP280_RELAX; + read_regs(curaddress, BMP280_REG_ALLDATA, 8); + return; + }*/ bmpstatus = BMP280_RDY; // data ready } @@ -382,8 +407,10 @@ int BMP280_getdata(float *T, float *P, float *H){ int32_t p = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4); int32_t t = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4); int32_t t_fine; - int32_t Temp = compTemp(t, &t_fine); - if(T) *T = ((float)Temp)/100.f; + if(T){ + int32_t Temp = compTemp(t, &t_fine); + *T = ((float)Temp)/100.f; + } if(P) *P = ((float)compPres(p, t_fine)) / 256.f; if(H){ int32_t h = (data[6] << 8) | data[7]; @@ -394,6 +421,8 @@ int BMP280_getdata(float *T, float *P, float *H){ // dewpoint calculation (T in degrC, H in percents) float Tdew(float T, float H){ + if(H < 1e-3) return -300.f; float gamma = 17.27f * T / (237.7f + T) + logf(H/100.f); - return (237.7f * gamma)/(17.27 - gamma); + if(fabsf(17.27f - gamma) < 1e-3) return -300.f; + return (237.7f * gamma)/(17.27f - gamma); } diff --git a/F3:F303/BME280/bme280.bin b/F3:F303/BME280/bme280.bin index 20a2ef0..f05986b 100755 Binary files a/F3:F303/BME280/bme280.bin and b/F3:F303/BME280/bme280.bin differ diff --git a/F3:F303/BME280/bme280.creator.user b/F3:F303/BME280/bme280.creator.user index 9a72567..c00d1f5 100644 --- a/F3:F303/BME280/bme280.creator.user +++ b/F3:F303/BME280/bme280.creator.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/F3:F303/BME280/hardware.c b/F3:F303/BME280/hardware.c index 3579757..f5a729c 100644 --- a/F3:F303/BME280/hardware.c +++ b/F3:F303/BME280/hardware.c @@ -24,8 +24,9 @@ static inline void gpio_setup(){ // USB - alternate function 14 @ pins PA11/PA12; SWD - AF0 @PA13/14 GPIOA->AFR[1] = AFRf(14, 11) | AFRf(14, 12); GPIOA->MODER = MODER_AF(11) | MODER_AF(12) | MODER_AF(13) | MODER_AF(14) | MODER_O(15); - GPIOB->MODER = MODER_O(0) | MODER_O(1); - GPIOB->ODR = 1; + GPIOB->MODER = MODER_O(0) | MODER_O(1) | MODER_O(2); + pin_set(GPIOB, 1<<1); + SPI_CS_1(); } void hw_setup(){ diff --git a/F3:F303/BME280/hardware.h b/F3:F303/BME280/hardware.h index fc241df..2b50da6 100644 --- a/F3:F303/BME280/hardware.h +++ b/F3:F303/BME280/hardware.h @@ -25,6 +25,10 @@ #define USBPU_ON() pin_clear(USBPU_port, USBPU_pin) #define USBPU_OFF() pin_set(USBPU_port, USBPU_pin) +// SPI_CS - PB2 (pin 20) +#define SPI_CS_1() pin_set(GPIOB, 1<<2) +#define SPI_CS_0() pin_clear(GPIOB, 1<<2) + extern volatile uint32_t Tms; void hw_setup(); diff --git a/F3:F303/BME280/main.c b/F3:F303/BME280/main.c index 82b790e..c9a1374 100644 --- a/F3:F303/BME280/main.c +++ b/F3:F303/BME280/main.c @@ -43,7 +43,7 @@ int main(void){ hw_setup(); USBPU_OFF(); USB_setup(); - BMP280_setup(0, 1); + //BMP280_setup(0, 1); uint32_t ctr = Tms, Tmeas = 0; USBPU_ON(); while(1){ @@ -57,20 +57,35 @@ int main(void){ const char *ans = parse_cmd(inbuff); if(ans) USB_sendstr(ans); } - BMP280_process(); - if(Tms - Tmeas > 9999){ - BMP280_status s = BMP280_get_status(); - float Temperature, Pressure, Humidity, Dewpoint; - if(s == BMP280_NOTINIT || s == BMP280_ERR) BMP280_init(); - else if(s == BMP280_RDY && BMP280_getdata(&Temperature, &Pressure, &Humidity)){ - Dewpoint = Tdew(Temperature, Humidity); - USB_sendstr("Tdeg="); USB_sendstr(float2str(Temperature, 2)); USB_sendstr("\nPpa="); - USB_sendstr(float2str(Pressure, 1)); - USB_sendstr("\nPmm="); USB_sendstr(float2str(Pressure * 0.00750062f, 1)); - USB_sendstr("\nH="); USB_sendstr(float2str(Humidity, 1)); - USB_sendstr("\nTdew="); USB_sendstr(float2str(Dewpoint, 1)); - newline(); - Tmeas += 10000; + BMP280_status s = BMP280_get_status(); + if(s != BMP280_NOTINIT){ + if(s == BMP280_ERR) BMP280_init(); + else{ + BMP280_process(); + s = BMP280_get_status(); // refresh status after processing + float Temperature, Pressure, Humidity, Dewpoint; + if(s == BMP280_RDY && BMP280_getdata(&Temperature, &Pressure, &Humidity)){ + Dewpoint = Tdew(Temperature, Humidity); + USB_sendstr("Tdeg="); USB_sendstr(float2str(Temperature, 2)); USB_sendstr("\nPpa="); + USB_sendstr(float2str(Pressure, 3)); + USB_sendstr("\nPmm="); USB_sendstr(float2str(Pressure * 0.00750062f, 2)); + USB_sendstr("\nH="); USB_sendstr(float2str(Humidity, 2)); + USB_sendstr("\nTdew="); USB_sendstr(float2str(Dewpoint, 1)); + newline(); + } + if(contmeas && (Tms - Tmeas > 999)){ + if(BMP280_start()) Tmeas = Tms; + } + } + } + if(i2c_scanmode){ + uint8_t addr; + int ok = i2c_scan_next_addr(&addr); + if(addr == I2C_ADDREND) USND("End scan"); + else if(ok){ + USB_sendstr(uhex2str(addr)); + USB_sendstr(" ("); USB_sendstr(u2str(addr)); + USB_sendstr(") - found device\n"); } } } diff --git a/F3:F303/BME280/proto.c b/F3:F303/BME280/proto.c index bc4207a..5169c26 100644 --- a/F3:F303/BME280/proto.c +++ b/F3:F303/BME280/proto.c @@ -19,6 +19,8 @@ #include #include +#include "BMP280.h" +#include "i2c.h" #include "spi.h" #include "strfunc.h" #include "usb_dev.h" @@ -29,11 +31,19 @@ static uint8_t locBuffer[LOCBUFFSZ]; static const char *ERR = "ERR\n", *OK = "OK\n"; extern volatile uint32_t Tms; +int contmeas = 0; // continuous measurements each 1s const char *helpstring = "https://github.com/eddyem/stm32samples/tree/master/F3:F303/xxx build#" BUILD_NUMBER " @ " BUILD_DATE "\n" - "i - [re]init SPI1\n" - "s - send up to 32 bytes of data and read answer\n" + "c - set/reset continuous measurements\n" + "s - send up to 32 bytes of data over SPI and read answer\n" + "Axi - init BME280 with address x (0/1) and interface i (I/S - I2C/SPI)\n" + "Fx- set filter to x (0..4)\n" + "I - [re]init I2C\n" + "Is - scan I2C bus\n" + "M - start measurement\n" + "Ovx - set oversampling of v(t, h or p) to x(0..5)\n" + "S - [re]init SPI1\n" "T - print current Tms\n" ; @@ -46,9 +56,9 @@ TRUE_INLINE uint16_t readNnumbers(const char *buf){ if(D > 0xff){ USND("Each number should be uint8_t"); return 0; } buf = nxt; locBuffer[N++] = (uint8_t) D&0xff; - USND("add byte: "); USND(uhex2str(D&0xff)); USND("\n"); + //USND("add byte: "); USND(uhex2str(D&0xff)); USND("\n"); } - USND("Send "); USND(u2str(N)); USND(" bytes\n"); + //USND("Send "); USND(u2str(N)); USND(" bytes\n"); return N; } @@ -62,23 +72,106 @@ TRUE_INLINE const char* spirdwr(const char *buf){ return NULL; } +TRUE_INLINE const char* bmeinint(const char *buf){ + buf = omit_spaces(buf); + char c = *buf; + if(c != '0' && c != '1') return "Wrong address\n"; + uint8_t addr = c - '0'; + buf = omit_spaces(buf + 1); + c = *buf; + uint8_t isI2C = 0; + switch(c){ + case 'i': + case 'I': + isI2C = 1; + case 's': + case 'S': + break; + default: + return "Wrong interface\n"; + } + BMP280_setup(addr, isI2C); + if(BMP280_init()){ + if(BMP280_read_ID(&addr)){ + if(addr == BMP280_CHIP_ID) return "found BMP280\n"; + else return "found BME280\n"; + }else return "Failed read ID\n"; + } + return ERR; +} + +TRUE_INLINE const char* setos(const char *buf){ + buf = omit_spaces(buf); + uint32_t U32; + void (*osfunc)(BMP280_Oversampling) = NULL; + switch(*buf){ + case 'h': // h_os + case 'H': + osfunc = BMP280_setOSh; + break; + case 'p': // p_os + case 'P': + osfunc = BMP280_setOSp; + break; + case 't': // t_os + case 'T': + osfunc = BMP280_setOSt; + break; + default: + return "Wrong OS function\n"; + } + buf = omit_spaces(buf+1); + if(!*buf) return "Need OS number\n"; + if(buf != getnum(buf, &U32) && U32 < BMP280_OVERSMAX){ + osfunc((BMP280_Oversampling)U32); + return OK; + } + return "Wrong OS number\n"; +} + const char *parse_cmd(const char *buf){ + uint32_t U32; // "long" commands if(buf[1]){ char c = *buf++; switch(c){ case 's': return spirdwr(buf); + case 'A': + return bmeinint(buf); + case 'F': + buf = omit_spaces(buf); + if(buf != getnum(buf, &U32) && U32 < BMP280_FILTERMAX){ + BMP280_setfilter((BMP280_Filter)U32); + return OK; + }else return ERR; + case 'I': + if(*buf == 's'){ + i2c_init_scan_mode(); + return "Start scan\n"; + }else return ERR; + case 'O': + return setos(buf); default: return buf; // echo input } } - /* switch(*buf){ - case '': - break; - }*/ // "short" commands switch(*buf){ - case 'i': + case 'c': + contmeas = !contmeas; + if(contmeas){ + if(BMP280_start()) return OK; + return ERR; + } + return OK; + case 'I': + i2c_setup(I2C_SPEED_400K); + return OK; + case 'M': + if(!BMP280_start()) return ERR; + else return OK; + break; + case 'S': spi_setup(); return OK; case 'T': diff --git a/F3:F303/BME280/proto.h b/F3:F303/BME280/proto.h index 3ee30ab..d1d28b5 100644 --- a/F3:F303/BME280/proto.h +++ b/F3:F303/BME280/proto.h @@ -18,5 +18,6 @@ #pragma once +extern int contmeas; char *parse_cmd(char *buf); diff --git a/F3:F303/BME280/spi.c b/F3:F303/BME280/spi.c index 56fa8f8..3c99255 100644 --- a/F3:F303/BME280/spi.c +++ b/F3:F303/BME280/spi.c @@ -20,15 +20,15 @@ #include "spi.h" #include // memcpy -#ifdef EBUG #include "usb_dev.h" +#ifdef EBUG #include "strfunc.h" #endif spiStatus spi_status = SPI_NOTREADY; #define WAITX(x) do{volatile uint32_t wctr = 0; while((x) && (++wctr < 360000)) IWDG->KR = IWDG_REFRESH; if(wctr==360000){ DBG("timeout"); return 0;}}while(0) -// init SPI +// init SPI @ ~280kHz (36MHz/128) void spi_setup(){ SPI1->CR1 = 0; // clear EN SPI1->CR2 = 0; @@ -65,7 +65,7 @@ void spi_deinit(){ spi_status = SPI_NOTREADY; } -int spi_waitbsy(){ +uint8_t spi_waitbsy(){ WAITX(SPI1->SR & SPI_SR_BSY); return 1; } @@ -76,12 +76,13 @@ int spi_waitbsy(){ * @param n - length of data * @return 0 if failed */ -int spi_writeread(uint8_t *data, uint8_t n){ +uint8_t spi_writeread(uint8_t *data, uint8_t n){ if(spi_status != SPI_READY || !data || !n){ DBG("not ready"); return 0; } // clear SPI Rx FIFO + spi_onoff(TRUE); for(int i = 0; i < 4; ++i) (void) SPI1->DR; for(int x = 0; x < n; ++x){ WAITX(!(SPI1->SR & SPI_SR_TXE)); @@ -89,11 +90,12 @@ int spi_writeread(uint8_t *data, uint8_t n){ WAITX(!(SPI1->SR & SPI_SR_RXNE)); data[x] = *((volatile uint8_t*)&SPI1->DR); } + spi_onoff(FALSE); // turn off SPI return 1; } -// read data through SPI in read-only mode -int spi_read(uint8_t *data, uint8_t n){ +// read data through SPI +uint8_t spi_read(uint8_t *data, uint8_t n){ if(spi_status != SPI_READY || !data || !n){ DBG("not ready"); return 0; @@ -102,12 +104,10 @@ int spi_read(uint8_t *data, uint8_t n){ for(int i = 0; i < 4; ++i) (void) SPI1->DR; spi_onoff(TRUE); for(int x = 0; x < n; ++x){ - if(x == n - 1) SPI1->CR1 &= ~SPI_CR1_RXONLY; // clear RXonly bit to stop CLK generation after next byte WAITX(!(SPI1->SR & SPI_SR_RXNE)); data[x] = *((volatile uint8_t*)&SPI1->DR); } spi_onoff(FALSE); // turn off SPI - SPI1->CR1 |= SPI_CR1_RXONLY; // and return RXonly bit return 1; } diff --git a/F3:F303/BME280/spi.h b/F3:F303/BME280/spi.h index 52e9f17..ecef67b 100644 --- a/F3:F303/BME280/spi.h +++ b/F3:F303/BME280/spi.h @@ -30,6 +30,6 @@ extern spiStatus spi_status; void spi_onoff(uint8_t on); void spi_deinit(); void spi_setup(); -int spi_waitbsy(); -int spi_writeread(uint8_t *data, uint8_t n); -int spi_read(uint8_t *data, uint8_t n); +uint8_t spi_waitbsy(); +uint8_t spi_writeread(uint8_t *data, uint8_t n); +uint8_t spi_read(uint8_t *data, uint8_t n); diff --git a/F3:F303/BME280/usb_dev.h b/F3:F303/BME280/usb_dev.h index b7bd929..605d34e 100644 --- a/F3:F303/BME280/usb_dev.h +++ b/F3:F303/BME280/usb_dev.h @@ -47,9 +47,9 @@ void linecoding_handler(usb_LineCoding *lc); #define RBINSZ (1024) #ifdef EBUG -#define DBG(x) USB_sendstr(x) +#define DBG(s) do{USB_sendstr(s); USB_putbyte('\n');}while(0) #else -#define DBG() +#define DBG(s) #endif #define newline() USB_putbyte('\n') diff --git a/F3:F303/BME280/version.inc b/F3:F303/BME280/version.inc index 691b49d..9d5676c 100644 --- a/F3:F303/BME280/version.inc +++ b/F3:F303/BME280/version.inc @@ -1,2 +1,2 @@ -#define BUILD_NUMBER "13" -#define BUILD_DATE "2025-10-02" +#define BUILD_NUMBER "33" +#define BUILD_DATE "2025-10-04"