diff --git a/examples/bme280/README.md b/examples/bme280/README.md new file mode 100644 index 0000000000000000000000000000000000000000..4325a1eb730bc29c97d3da3c6d5c7d9b1e71f539 --- /dev/null +++ b/examples/bme280/README.md @@ -0,0 +1,16 @@ +# BME280 sensor example + +Pinout is according to the C source: MOSI - 23, MISO - 19, CLK - 18, CS = 5: + +```c + struct spi bme280 = {.mosi = 23, .miso = 19, .clk = 18, .cs = {5, -1, -1}}; +``` + +Build, flash and monitor: + +``` +Chip ID: 96, expecting 96 +Temp: 23.69 +Chip ID: 96, expecting 96 +Temp: 25.5 +``` diff --git a/examples/bme280/main.c b/examples/bme280/main.c index 0206332919d26320f6ed543187860051c9b34aeb..25e11cba0f3ddddeb4ed1c4d54be354cd7c9f919 100644 --- a/examples/bme280/main.c +++ b/examples/bme280/main.c @@ -1,16 +1,62 @@ #include <sdk.h> -static int led = 2, pin = 4; +static unsigned readn(struct spi *spi, uint8_t reg, int n) { + unsigned rx = 0; + spi_begin(spi, 0); + spi_txn(spi, reg | 0x80); + for (int i = 0; i < n; i++) rx <<= 8, rx |= spi_txn(spi, 0); + spi_end(spi, 0); + return rx; +} + +static void write8(struct spi *spi, uint8_t reg, uint8_t val) { + spi_begin(spi, 0); + spi_txn(spi, (uint8_t)(reg & ~0x80)); + spi_txn(spi, val); + spi_end(spi, 0); +} + +uint16_t swap16(uint16_t val) { + uint8_t data[2] = {0, 0}; + memcpy(&data, &val, sizeof(data)); + return (uint16_t)((uint16_t) data[1] | (((uint16_t) data[0]) << 8)); +} + +// Taken from the BME280 datasheet, 4.2.3 +int32_t read_temp(struct spi *spi) { + int32_t t = (int32_t)(readn(spi, 0xfa, 3) >> 4); // Read temperature reg + + uint16_t c1 = (uint16_t) readn(spi, 0x88, 2); // dig_T1 + uint16_t c2 = (uint16_t) readn(spi, 0x8a, 2); // dig_T2 + uint16_t c3 = (uint16_t) readn(spi, 0x8c, 2); // dig_T3 + + int32_t t1 = (int32_t) swap16(c1); + int32_t t2 = (int32_t)(int16_t) swap16(c2); + int32_t t3 = (int32_t)(int16_t) swap16(c3); + + int32_t var1 = ((((t >> 3) - (t1 << 1))) * t2) >> 11; + int32_t var2 = (((((t >> 4) - t1) * ((t >> 4) - t1)) >> 12) * t3) >> 14; + + return ((var1 + var2) * 5 + 128) >> 8; +} int main(void) { wdt_disable(); - gpio_output(led); - gpio_input(pin); + + struct spi bme280 = {.mosi = 23, .miso = 19, .clk = 18, .cs = {5, -1, -1}}; + spi_init(&bme280); + + write8(&bme280, 0xe0, 0xb6); // Soft reset + spin(999999); // Wait until reset + write8(&bme280, 0xf4, 0); // REG_CONTROL, MODE_SLEEP + write8(&bme280, 0xf5, (3 << 5)); // REG_CONFIG, filter = off, 20ms + write8(&bme280, 0xf4, (1 << 5) | 3); // REG_CONFIG, MODE_NORMAL for (;;) { - sdk_log("in: %d\n", gpio_read(pin)); - gpio_toggle(led); - spin(2999999); + sdk_log("Chip ID: %d, expecting 96\n", readn(&bme280, 0xd0, 1)); + int temp = read_temp(&bme280); + sdk_log("Temp: %d.%d\n", temp / 100, temp % 100); + spin(9999999); } return 0; diff --git a/include/gpio.h b/include/gpio.h index bc5ab473bc98fcbaab0fa70a7a1fdd24d65631e0..f932665af84e3dd740ee9b223a3ff80c4529bb57 100644 --- a/include/gpio.h +++ b/include/gpio.h @@ -7,7 +7,7 @@ #define GPIO_IN1_REG REG(0X3ff44040) // Pins 32-39 #define GPIO_ENABLE1_REG REG(0X3ff4402c) // Pins 32-39 -static inline void gpio_output_enable(int pin, int enable) { +static inline void gpio_output_enable(int pin, bool enable) { volatile unsigned long *r = GPIO_ENABLE_REG; if (pin > 31) pin -= 31, r = GPIO_ENABLE1_REG; r[0] &= ~BIT(pin); @@ -19,7 +19,7 @@ static inline void gpio_output(int pin) { gpio_output_enable(pin, 1); } -static inline void gpio_write(int pin, int value) { +static inline void gpio_write(int pin, bool value) { volatile unsigned long *r = GPIO_OUT_REG; if (pin > 31) pin -= 31, r = GPIO_OUT1_REG; r[0] &= ~BIT(pin); // Clear first @@ -41,10 +41,10 @@ static inline void gpio_input(int pin) { volatile unsigned long *mux = REG(0X3ff49000); if (pin < 0 || pin > (int) sizeof(map) || map[pin] == 0) return; gpio_output_enable(pin, 0); // Disable output - mux[pin] |= BIT(9); // Enable input + mux[map[pin]] |= BIT(9); // Enable input } -static inline int gpio_read(int pin) { +static inline bool gpio_read(int pin) { volatile unsigned long *r = GPIO_IN_REG; if (pin > 31) pin -= 31, r = GPIO_IN1_REG; return r[0] & BIT(pin) ? 1 : 0; diff --git a/include/sdk.h b/include/sdk.h index 990d11270cc5726b44c161e35c2b6f73a7cc3cf4..6b4e23f7b859919f5904db066ed93d48add41a86 100644 --- a/include/sdk.h +++ b/include/sdk.h @@ -6,6 +6,8 @@ #include <assert.h> #include <errno.h> #include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> #include <stdlib.h> #include <string.h> diff --git a/include/spi.h b/include/spi.h index fb6247da85fc9300835c056ed76e47489ba05b7c..f351d658d096b89ee76a95807b1cced86b69fc9b 100644 --- a/include/spi.h +++ b/include/spi.h @@ -1,6 +1,15 @@ struct spi { - int miso, mosi, clk, freq; + int miso, mosi, clk, cs[3]; }; -int spi_init(struct spi *spi); -int spi_txn(struct spi *spi); +bool spi_init(struct spi *spi); +unsigned char spi_txn(struct spi *spi, unsigned char tx); + +static inline void spi_begin(struct spi *spi, int cs) { + gpio_write(spi->cs[cs], 0); +} + +static inline void spi_end(struct spi *spi, int cs) { + gpio_write(spi->cs[cs], 1); +} + diff --git a/src/libc.c b/src/libc.c index 54da7c071df8c29f516904d55cbe9cf059e297f4..d0bb4ea63b254f3dbd2689ae3ccf1d7382424c1f 100644 --- a/src/libc.c +++ b/src/libc.c @@ -45,6 +45,12 @@ void *memset(void *dest, int c, size_t n) { return dest; } +void *memcpy(void *dst, const void *src, size_t len) { + unsigned char *d = dst, *s = (unsigned char *) src; + for (size_t i = 0; i < len; i++) d[i] = s[i]; + return dst; +} + char *strcpy(char *dst, const char *src) { for (size_t i = 0; src[i] != '\0'; i++) dst[i] = src[i]; return dst; diff --git a/src/spi.c b/src/spi.c index 7ebf563e3f581604622a18d380c824d45ae715e8..d82f7269eea1e484dab92e522c7719f6ed318f37 100644 --- a/src/spi.c +++ b/src/spi.c @@ -3,12 +3,36 @@ #include <sdk.h> -int spi_init(struct spi *spi) { - (void) spi; - return 0; +// TODO(cpq): make this configurable with accurate frequency +static inline void spi_clock_delay(void) { + spin(9); } -int spi_txn(struct spi *spi) { - (void) spi; - return 0; +bool spi_init(struct spi *spi) { + if (spi->miso < 0 || spi->mosi < 0 || spi->clk < 0) return false; + gpio_input(spi->miso); + gpio_output(spi->mosi); + gpio_output(spi->clk); + for (size_t i = 0; i < sizeof(spi->cs) / sizeof(spi->cs[0]); i++) { + if (spi->cs[i] < 0) continue; + gpio_output(spi->cs[i]); + gpio_write(spi->cs[i], 1); + } + return true; +} + +// Send a byte, and return a received byte +unsigned char spi_txn(struct spi *spi, unsigned char tx) { + unsigned char rx = 0; + for (int i = 0; i < 8; i++) { + gpio_write(spi->mosi, tx & 0x80); // Set mosi + spi_clock_delay(); // Wait half cycle + gpio_write(spi->clk, 1); // Clock high + rx = (unsigned char) (rx << 1); // "rx <<= 1" gives warning?? + if (gpio_read(spi->miso)) rx |= 1; // Read mosi + spi_clock_delay(); // Wait half cycle + gpio_write(spi->clk, 0); // Clock low + tx = (unsigned char) (tx << 1); // Again, avoid warning + } + return rx; // Return the received byte }