Compare commits

...

3 Commits

Author SHA1 Message Date
45b3678606 First test draft 2019-10-17 23:18:18 +02:00
cff98762be Add dirty test draft 2019-10-17 20:18:09 +02:00
abdabd8eb7 Fix definition in STM header file and add header files for drivers 2019-10-17 20:17:52 +02:00
10 changed files with 568 additions and 15 deletions

10
.gitignore vendored
View File

@@ -1,4 +1,11 @@
memmap.map memmap.map
*.config
*.creator
*.cxxflags
*.files
*.includes
*.cflags
*.o *.o
*.d *.d
*.elf *.elf
@@ -6,3 +13,6 @@ memmap.map
*.pro *.pro
*.user *.user
*.user* *.user*
measurement_data
*.jdebug

View File

@@ -5,7 +5,7 @@
#Add Files and Folders below######################################################### #Add Files and Folders below#########################################################
CFILES = main.c syscalls/syscalls.c setup/system_init.c startup/startup_stm32f0xx.c CFILES = main.c syscalls/syscalls.c setup/system_init.c startup/startup_stm32f0xx.c
ASFILES = ASFILES =
INCLUDEPATH = -Iinclude -Iinclude/cmsis INCLUDEPATH = -Iinclude -Iinclude/cmsis -Ibme680-driver-fork
target = bme680-air-meter target = bme680-air-meter
@@ -17,7 +17,7 @@ mapfile = memmap
##Custom Files### ##Custom Files###
CFILES += bme680-driver-fork/bme680.c CFILES += bme680-driver-fork/bme680.c lcd.c delay.c meas.c
################################################################################### ###################################################################################
@@ -28,10 +28,10 @@ SIZE=arm-none-eabi-size
LFLAGS = -mlittle-endian -mthumb -mcpu=cortex-m0 -mthumb-interwork LFLAGS = -mlittle-endian -mthumb -mcpu=cortex-m0 -mthumb-interwork
LFLAGS += -mfloat-abi=soft --disable-newlib-supplied-syscalls -nostartfiles LFLAGS += -mfloat-abi=soft --disable-newlib-supplied-syscalls -nostartfiles
LFLAGS += -Tstartup/stm32f030.ld -Wl,-Map=$(mapfile).map -Wl,--gc-sections -g -Os LFLAGS += -Tstartup/stm32f030.ld -Wl,-Map=$(mapfile).map -Wl,--gc-sections -g -O0
CFLAGS = -c -fmessage-length=0 -mlittle-endian -mthumb -mcpu=cortex-m0 -mthumb-interwork CFLAGS = -c -fmessage-length=0 -mlittle-endian -mthumb -mcpu=cortex-m0 -mthumb-interwork
CFLAGS += -mfloat-abi=soft -nostartfiles -Wall -g -Os CFLAGS += -mfloat-abi=soft -nostartfiles -Wall -g -O0
#################################################################################### ####################################################################################

9
delay.c Normal file
View File

@@ -0,0 +1,9 @@
#include <delay.h>
volatile uint32_t tick;
void delay_ms(uint32_t ms)
{
tick = 0;
while (tick < ms);
}

13
include/delay.h Normal file
View File

@@ -0,0 +1,13 @@
#ifndef __DELAY_H__
#define __DELAY_H__
#include <stdint.h>
extern volatile uint32_t tick;
/**
* @brief wait for specific time in ms. May not be caleed from interrupt context
*/
void delay_ms(uint32_t ms);
#endif /* __DELAY_H__ */

43
include/lcd.h Normal file
View File

@@ -0,0 +1,43 @@
#ifndef __LCD_H__
#define __LCD_H__
#include <stm32f0xx.h>
#define LCD_DPORT (GPIOA)
#define LCD_DATA_BIT_OFFSET (0)
#define LCD_RS (9)
#define LCD_E (10)
#define LCD_DATA_MASK (0xFU << LCD_DATA_BIT_OFFSET)
#define LCD_RS_MASK (1U << LCD_RS)
#define LCD_E_MASK (1U << LCD_E)
/**
* @brief Initialize 4 bit LCD mode. GPIOs have to be set up prior to any call of this function
*/
void lcd_init(void);
/**
* @brief Clear display
*/
void lcd_clear(void);
/**
* @brief Set cursor position to 0/0
*/
void lcd_home(void);
/**
* @brief Set cursor to position \p x \p y
* @param x Position in line
* @param y Line
*/
void lcd_setcursor(uint8_t x, uint8_t y);
/**
* @brief Write string to current cursor position
* @param String to write
*/
void lcd_string(const char *data);
#endif /* __LCD_H__ */

22
include/meas.h Normal file
View File

@@ -0,0 +1,22 @@
#ifndef __MEAS_H__
#define __MEAS_H__
#include <bme680_defs.h>
#include <stdbool.h>
/**
* @brief Initialize sensor
* @return 0 if successful
*/
int meas_init_without_gas(void);
/**
* @brief Do a single measurement
* @param gas_enable select if gas measurement should be done
* @param meas_data read data
* @param ambient_temp Ambient Temperature
* @return 0 if successful
*/
int meas_do(bool gas_enable, struct bme680_field_data *meas_data, int8_t ambient_temp);
#endif /* __MEAS_H__ */

View File

@@ -365,8 +365,15 @@ typedef struct
{ {
__IO uint32_t CR1; /*!< SPI Control register 1 (not used in I2S mode), Address offset: 0x00 */ __IO uint32_t CR1; /*!< SPI Control register 1 (not used in I2S mode), Address offset: 0x00 */
__IO uint32_t CR2; /*!< SPI Control register 2, Address offset: 0x04 */ __IO uint32_t CR2; /*!< SPI Control register 2, Address offset: 0x04 */
__IO uint32_t SR; /*!< SPI Status register, Address offset: 0x08 */ __IO uint32_t SR; /*!< SPI Status register, Address offset: 0x08 */
__IO uint32_t DR; /*!< SPI data register, Address offset: 0x0C */ union DR_ {
__IO uint16_t DR16; /*!< SPI data register, Address offset: 0x0C */
struct DR8_ {
__IO uint8_t DR8_1;
__IO uint8_t DR8_2;
} DR8;
} DR;
__IO uint16_t DR_DUMMY;
__IO uint32_t CRCPR; /*!< SPI CRC polynomial register (not used in I2S mode), Address offset: 0x10 */ __IO uint32_t CRCPR; /*!< SPI CRC polynomial register (not used in I2S mode), Address offset: 0x10 */
__IO uint32_t RXCRCR; /*!< SPI Rx CRC register (not used in I2S mode), Address offset: 0x14 */ __IO uint32_t RXCRCR; /*!< SPI Rx CRC register (not used in I2S mode), Address offset: 0x14 */
__IO uint32_t TXCRCR; /*!< SPI Tx CRC register (not used in I2S mode), Address offset: 0x18 */ __IO uint32_t TXCRCR; /*!< SPI Tx CRC register (not used in I2S mode), Address offset: 0x18 */

209
lcd.c Normal file
View File

@@ -0,0 +1,209 @@
#include <lcd.h>
#include <delay.h>
static void lcd_port_clear(void)
{
LCD_DPORT->ODR &= ~(LCD_E_MASK);
LCD_DPORT->ODR &= ~(LCD_DATA_MASK | LCD_RS_MASK | LCD_E_MASK);
}
static void lcd_enable(void)
{
__ASM("nop");
__ASM("nop");
__ASM("nop");
LCD_DPORT->ODR |= LCD_E_MASK;
__ASM("nop");
__ASM("nop");
__ASM("nop");
__ASM("nop");
__ASM("nop");
__ASM("nop");
LCD_DPORT->ODR &= ~LCD_E_MASK;
__ASM("nop");
__ASM("nop");
__ASM("nop");
__ASM("nop");
__ASM("nop");
__ASM("nop");
}
static void lcd_out(uint8_t data)
{
LCD_DPORT->ODR &= ~(LCD_DATA_MASK);
LCD_DPORT->ODR |= (data << LCD_DATA_BIT_OFFSET) & LCD_DATA_MASK;
}
static void lcd_data(uint8_t data)
{
lcd_port_clear();
LCD_DPORT->ODR |= LCD_RS_MASK;
lcd_out((data>>4) & 0xFU);
lcd_enable();
lcd_out(data & 0xFU);
lcd_enable();
delay_ms(1);
}
static void lcd_command(uint8_t data)
{
lcd_port_clear();
lcd_out((data>>4) & 0xFU);
lcd_enable();
lcd_out(data & 0xFU);
lcd_enable();
delay_ms(1);
}
#define LCD_DDADR_LINE1 0x00
#define LCD_DDADR_LINE2 0x40
#define LCD_DDADR_LINE3 0x10
#define LCD_DDADR_LINE4 0x50
// Clear Display -------------- 0b00000001
#define LCD_CLEAR_DISPLAY 0x01
// Cursor Home ---------------- 0b0000001x
#define LCD_CURSOR_HOME 0x02
// Set Entry Mode ------------- 0b000001xx
#define LCD_SET_ENTRY 0x04
#define LCD_ENTRY_DECREASE 0x00
#define LCD_ENTRY_INCREASE 0x02
#define LCD_ENTRY_NOSHIFT 0x00
#define LCD_ENTRY_SHIFT 0x01
// Set Display ---------------- 0b00001xxx
#define LCD_SET_DISPLAY 0x08
#define LCD_DISPLAY_OFF 0x00
#define LCD_DISPLAY_ON 0x04
#define LCD_CURSOR_OFF 0x00
#define LCD_CURSOR_ON 0x02
#define LCD_BLINKING_OFF 0x00
#define LCD_BLINKING_ON 0x01
// Set Shift ------------------ 0b0001xxxx
#define LCD_SET_SHIFT 0x10
#define LCD_CURSOR_MOVE 0x00
#define LCD_DISPLAY_SHIFT 0x08
#define LCD_SHIFT_LEFT 0x00
#define LCD_SHIFT_RIGHT 0x04
// Set Function --------------- 0b001xxxxx
#define LCD_SET_FUNCTION 0x20
#define LCD_FUNCTION_4BIT 0x00
#define LCD_FUNCTION_8BIT 0x10
#define LCD_FUNCTION_1LINE 0x00
#define LCD_FUNCTION_2LINE 0x08
#define LCD_FUNCTION_5X7 0x00
#define LCD_FUNCTION_5X10 0x04
#define LCD_SOFT_RESET 0x30
// Set CG RAM Address --------- 0b01xxxxxx (Character Generator RAM)
#define LCD_SET_CGADR 0x40
#define LCD_GC_CHAR0 0
#define LCD_GC_CHAR1 1
#define LCD_GC_CHAR2 2
#define LCD_GC_CHAR3 3
#define LCD_GC_CHAR4 4
#define LCD_GC_CHAR5 5
#define LCD_GC_CHAR6 6
#define LCD_GC_CHAR7 7
// Set DD RAM Address --------- 0b1xxxxxxx (Display Data RAM)
#define LCD_SET_DDADR 0x80
void lcd_clear(void)
{
lcd_command(LCD_CLEAR_DISPLAY);
delay_ms(3);
}
void lcd_home( void )
{
lcd_command(LCD_CURSOR_HOME);
delay_ms(3);
}
void lcd_setcursor( uint8_t x, uint8_t y )
{
uint8_t data;
switch (y)
{
case 0: // 1. Zeile
data = LCD_SET_DDADR + LCD_DDADR_LINE1 + x;
break;
case 1: // 2. Zeile
data = LCD_SET_DDADR + LCD_DDADR_LINE2 + x;
break;
case 2: // 3. Zeile
data = LCD_SET_DDADR + LCD_DDADR_LINE3 + x;
break;
case 3: // 4. Zeile
data = LCD_SET_DDADR + LCD_DDADR_LINE4 + x;
break;
default:
return; // für den Fall einer falschen Zeile
}
lcd_command(data);
}
void lcd_string(const char *data)
{
while(*data != '\0') {
lcd_data((uint8_t)*data++);
}
}
void lcd_init(void)
{
int i;
lcd_port_clear();
delay_ms(100);
LCD_DPORT->ODR |= (0x3 << LCD_DATA_BIT_OFFSET);
for (i = 0; i < 3; i++) {
lcd_enable();
delay_ms(5);
}
// Set 4 Bit mode
lcd_port_clear();
LCD_DPORT->ODR |= (0x2<<LCD_DATA_BIT_OFFSET);
lcd_enable();
delay_ms(2);
// 4-bit Modus / 2 Zeilen / 5x7
lcd_command( LCD_SET_FUNCTION |
LCD_FUNCTION_4BIT |
LCD_FUNCTION_2LINE |
LCD_FUNCTION_5X7 );
// Display ein / Cursor aus / Blinken aus
lcd_command( LCD_SET_DISPLAY |
LCD_DISPLAY_ON |
LCD_CURSOR_OFF |
LCD_BLINKING_OFF);
// Cursor inkrement / kein Scrollen
lcd_command( LCD_SET_ENTRY |
LCD_ENTRY_INCREASE |
LCD_ENTRY_NOSHIFT );
lcd_clear();
}

127
main.c
View File

@@ -1,27 +1,136 @@
#include <stm32f0xx.h> #include <stm32f0xx.h>
#include "bme680-driver-fork/bme680.h" #include <delay.h>
#include <lcd.h>
#include <stdlib.h>
#include <stdio.h>
#include <meas.h>
unsigned int i = 0x12345678; unsigned int i = 0x12345678;
unsigned char c = 2; unsigned char c = 2;
#define OUTPUT(pin) (0x01 << (pin * 2)) #define OUTPUT(pin) (0x01U << (pin * 2))
#define PULLUP(pin) (0x1U << (pin* 2))
#define ALTFUNC(pin) ((0x2) << (pin * 2)) #define ALTFUNC(pin) ((0x2) << (pin * 2))
#define PINMASK(pin) ((0x3) << (pin * 2)) #define PINMASK(pin) ((0x3) << (pin * 2))
#define SETAF(PORT,PIN,AF) PORT->AFR[(PIN < 8 ? 0 : 1)] |= AF << ((PIN < 8 ? PIN : (PIN - 8)) * 4) #define SETAF(PORT,PIN,AF) PORT->AFR[(PIN < 8 ? 0 : 1)] |= AF << ((PIN < 8 ? PIN : (PIN - 8)) * 4)
static void setup_hw(void)
{
RCC->AHBENR |= RCC_AHBENR_GPIOFEN | RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN;
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
GPIOA->MODER |= OUTPUT(4) | ALTFUNC(5) | ALTFUNC(7) | ALTFUNC(6) | OUTPUT(0) | OUTPUT(1) | OUTPUT(2) | OUTPUT(3) | OUTPUT(9) | OUTPUT(10);
SETAF(GPIOA, 5, 0);
SETAF(GPIOA, 6, 0);
SETAF(GPIOA, 7, 0);
GPIOF->MODER |= OUTPUT(0);
GPIOF->PUPDR |= PULLUP(1);
GPIOF->ODR &= ~(1<<0);
GPIOB->MODER |= OUTPUT(1);
GPIOB->ODR &= ~(1<<1);
GPIOA->ODR |= (1<<4);
SPI1->CR1 = SPI_CR1_BR_2 | SPI_CR1_MSTR | SPI_CR1_SSM | SPI_CR1_SSI;
SPI1->CR1 |= SPI_CR1_SPE;
/* Configure Systick for 1ms interval */
SysTick_Config(8000/*00*/);
lcd_init();
}
static void format(int temp, char *string, uint8_t decimals, uint8_t digits)
{
int digit;
for (digit = decimals+digits; digit >= 1; digit--) {
if (digit >= digits+1)
string[digit] = (temp % 10) + 0x30;
else
string[digit-1] = (temp % 10) + 0x30;
temp /= 10;
}
string[digits] = '.';
string[decimals+digits+1] = 0x00;
}
static void print_data_to_display(int32_t temp, uint32_t pressure, uint32_t humidity)
{
char lcd_line[17];
lcd_clear();
lcd_home();
lcd_string("Temp: ");
format(temp, lcd_line, 2, 2);
lcd_string(lcd_line);
lcd_setcursor(0, 1);
lcd_string("RH: ");
format((int)humidity, lcd_line, 3, 2);
lcd_string(lcd_line);
lcd_setcursor(0, 2);
lcd_string("Pr.: ");
format((int)pressure, lcd_line, 2, 4);
lcd_string(lcd_line);
}
int main(void) { int main(void) {
RCC->AHBENR |= RCC_AHBENR_GPIOFEN; struct bme680_field_data data;
GPIOF->MODER |= OUTPUT(0); int8_t ambient_temp = 25;
GPIOF->ODR |= (1<<0); int32_t temp_calib;
int i;
SysTick_Config(800000); setup_hw();
while(1) { meas_init_without_gas();
i++;
temp_calib = 0;
lcd_home();
lcd_string("Initializing...");
for (i = 0; i < 8; i++) {
i = 0;
delay_ms(1000);
if (meas_do(false, &data, ambient_temp)) {
/* Measurement failed. retry */
i--;
continue;
}
temp_calib += data.temperature;
ambient_temp = (int8_t)(data.temperature / 100);
print_data_to_display(data.temperature, data.pressure, data.humidity);
} }
temp_calib /= 8;
}
void HardFault_Handler(void)
{
while(1);
} }
void SysTick_Handler(void) { void SysTick_Handler(void) {
static int internal_tick = 0;
static volatile uint8_t backlight_counter;
/* Blink bad air LED */ /* Blink bad air LED */
GPIOF->ODR ^= (1<<0); tick++;
internal_tick++;
if (!(GPIOF->IDR & (1U<<1))) {
backlight_counter = 30;
GPIOB->ODR |= (1U<<1);
}
if (internal_tick > 200) {
internal_tick = 0;
if (backlight_counter > 0) {
backlight_counter--;
} else if (backlight_counter == 0) {
GPIOB->ODR &= ~(1U<<1);
}
//GPIOF->ODR ^= (1<<0);
}
} }

131
meas.c Normal file
View File

@@ -0,0 +1,131 @@
#include <meas.h>
#include <stm32f0xx.h>
#include <delay.h>
#include "bme680-driver-fork/bme680.h"
static struct bme680_dev gas_sensor;
static uint8_t spi_transfer(uint8_t out_data)
{
while(SPI1->SR & SPI_SR_BSY);
SPI1->DR.DR8.DR8_1 = out_data;
__DSB();
while((SPI1->SR & SPI_SR_BSY) || !(SPI1->SR & SPI_SR_TXE));
return (uint8_t)(SPI1->DR.DR8.DR8_1 & 0xFF);
}
static int8_t write_spi(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, uint16_t len)
{
(void)dev_id;
int i;
GPIOA->ODR &= ~(1U<<4);
spi_transfer(reg_addr);
for (i = 0; i < len; i++)
spi_transfer(reg_data[i]);
GPIOA->ODR |= (1U<<4);
return 0;
}
static int8_t read_spi(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, uint16_t len)
{
(void)dev_id;
int i;
GPIOA->ODR &= ~(1U<<4);
spi_transfer(reg_addr);
for (i = 0; i < len; i++)
reg_data[i] = spi_transfer(0x00);
GPIOA->ODR |= (1U<<4);
return 0;
}
int meas_init_without_gas(void)
{
int ret;
gas_sensor.dev_id = 0;
gas_sensor.intf = BME680_SPI_INTF;
gas_sensor.read = read_spi;
gas_sensor.write = write_spi;
gas_sensor.delay_ms = delay_ms;
gas_sensor.amb_temp = 25;
ret = (int)bme680_init(&gas_sensor);
if (ret)
return ret;
uint8_t set_required_settings;
/* Set the temperature, pressure and humidity settings */
gas_sensor.tph_sett.os_hum = BME680_OS_8X;
gas_sensor.tph_sett.os_pres = BME680_OS_8X;
gas_sensor.tph_sett.os_temp = BME680_OS_8X;
gas_sensor.tph_sett.filter = BME680_FILTER_SIZE_7;
/* Set the remaining gas sensor settings and link the heating profile */
gas_sensor.gas_sett.run_gas = BME680_DISABLE_GAS_MEAS;
/* Create a ramp heat waveform in 3 steps */
gas_sensor.gas_sett.heatr_temp = 320; /* degree Celsius */
gas_sensor.gas_sett.heatr_dur = 150; /* milliseconds */
/* Select the power mode */
/* Must be set before writing the sensor configuration */
gas_sensor.power_mode = BME680_FORCED_MODE;
/* Set the required sensor settings needed */
set_required_settings = BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_FILTER_SEL | BME680_GAS_SENSOR_SEL;
/* Set the desired sensor configuration */
ret = (int)bme680_set_sensor_settings(set_required_settings,&gas_sensor);
return ret;
}
int meas_do(bool gas_enable, struct bme680_field_data *meas_data, int8_t ambient_temp)
{
uint16_t meas_duration;
int res;
if (!meas_data)
return -100;
gas_sensor.power_mode = BME680_FORCED_MODE;
gas_sensor.gas_sett.run_gas = (gas_enable ? BME680_RUN_GAS_ENABLE : BME680_RUN_GAS_DISABLE);
gas_sensor.amb_temp = ambient_temp;
res = (int)bme680_set_sensor_settings(BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL |
BME680_FILTER_SEL | BME680_GAS_SENSOR_SEL,
&gas_sensor);
/* Set the power mode */
res = (int)bme680_set_sensor_mode(&gas_sensor);
if (res)
return res;
bme680_get_profile_dur(&meas_duration, &gas_sensor);
delay_ms(meas_duration);
res = (int)bme680_get_sensor_data(meas_data, &gas_sensor);
if (res)
return res;
gas_sensor.power_mode = BME680_SLEEP_MODE;
res = (int)bme680_set_sensor_mode(&gas_sensor);
return res;
}