diff options
Diffstat (limited to 'src/glutt-o-logique')
23 files changed, 2882 insertions, 0 deletions
diff --git a/src/glutt-o-logique/FreeRTOSConfig.h b/src/glutt-o-logique/FreeRTOSConfig.h new file mode 100644 index 0000000..8d6f128 --- /dev/null +++ b/src/glutt-o-logique/FreeRTOSConfig.h @@ -0,0 +1,3 @@ +#include "../../../common/src/Core/FreeRTOSConfig.h" + +#define configCHECK_FOR_STACK_OVERFLOW 2 // Default: 2 diff --git a/src/glutt-o-logique/Makefile b/src/glutt-o-logique/Makefile new file mode 100644 index 0000000..d9ff944 --- /dev/null +++ b/src/glutt-o-logique/Makefile @@ -0,0 +1,133 @@ +### +# GNU ARM Embedded Toolchain +CC=arm-none-eabi-gcc +LD=arm-none-eabi-ld +AR=arm-none-eabi-ar +AS=arm-none-eabi-as +CP=arm-none-eabi-objcopy +OD=arm-none-eabi-objdump +SIZE=arm-none-eabi-size + +### +# Directory Structure +BINDIR=bin +SRCDIR=. + +SOURCES=$(shell find -L $(SRCDIR) -name '*.s') +SOURCES+=$(shell find -L $(SRCDIR) -name '*.c') +HEADERS=$(shell find -L $(SRCDIR) -name '*.h') + +INC=$(shell find -L $(SRCDIR) -name '*.h' -exec dirname {} \; | uniq) +INC+=../common/includes +INCLUDES=$(INC:%=-I%) + +# Create object list +OBJECTS=$(SOURCES:%.c=obj/%.o) + +# Define output files ELF & IHEX +BINELF=outp.elf +BINHEX=outp.hex + +### +# MCU FLAGS +MCFLAGS=-mcpu=cortex-m4 -mthumb -mlittle-endian \ +-mfpu=fpv4-sp-d16 -mfloat-abi=softfp -mthumb-interwork +# COMPILE FLAGS +DEFS=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DARM_MATH_CM4 -D__FPU_PRESENT=1 +CFLAGS =-Wall -ggdb -std=c99 -c $(MCFLAGS) $(DEFS) $(INCLUDES) +# LINKER FLAGS +LDSCRIPT= $(SRCDIR)/bsp/stm32_flash.ld +LDFLAGS =-T $(LDSCRIPT) --specs=nosys.specs $(MCFLAGS) -Wl,-Map=$(BINDIR)/outp.map + +### +# Optimizations +OPT?='O2 O3 O6' +# O1 and O4 are irrelevant +# O5 breaks FreeRTOS somehow +# I'm not trusting O7 + +ifneq ($(filter O1,$(OPT)),) +CXXFLAGS+=-fno-exceptions # Uncomment to disable exception handling +DEFS+=-DNO_EXCEPTIONS # The source code has to comply with this rule +endif + +ifneq ($(filter O2,$(OPT)),) +CFLAGS+=-Os # Optimize for size https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html +CXXFLAGS+=-Os +LDFLAGS+=-Os # Optimize for size https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html +endif + +ifneq ($(filter O3,$(OPT)),) +CFLAGS+=-ffunction-sections -fdata-sections # Place each function or data item into its own section in the output file +CXXFLAGS+=-ffunction-sections -fdata-sections # -||- +LDFLAGS+=-Wl,-gc-sections # Remove isolated unused sections +endif + +ifneq ($(filter O4,$(OPT)),) +CFLAGS+=-fno-builtin # Disable C++ exception handling +CXXFLAGS+=-fno-builtin # Disable C++ exception handling +endif + +ifneq ($(filter O5,$(OPT)),) +CFLAGS+=-flto # Enable link time optimization +CXXFLAGS+=-flto # Enable link time optimization +LDFLAGS+=-flto # Enable link time optimization +endif + +ifneq ($(filter O6,$(OPT)),) +CXXFLAGS+=-fno-rtti # Disable type introspection +endif + +ifneq ($(findstring O7,$(OPT)),) +LDFLAGS+=--specs=nano.specs # Use size optimized newlib +endif + +### +# Build Rules +.PHONY: all release debug clean + +all: release + +release: $(BINDIR)/$(BINHEX) + +debug: CFLAGS+=-g +debug: LDFLAGS+=-g +debug: release + +$(BINDIR)/$(BINHEX): $(BINDIR)/$(BINELF) + $(CP) -O ihex $< $@ + +$(BINDIR)/$(BINELF): vc.h $(OBJECTS) + $(CC) $(LDFLAGS) $(OBJECTS) -o $@ + $(SIZE) $(BINDIR)/$(BINELF) + +dir_guard=@mkdir -p $(@D) + +obj/%.o: %.c $(HEADERS) + $(dir_guard) + @echo [CC] $< + @$(CC) $(CFLAGS) $< -o $@ + +obj/%.o: %.s $(HEADERS) + $(dir_guard) + @echo [AS] $< + @$(CC) $(CFLAGS) $< -o $@ + +vc.h: ../../.git/logs/HEAD + echo "// This file is generated by Makefile." > vc.h + echo "// Do not edit this file!" >> vc.h + git log -1 --format="format:#define GIT_VERSION \"%h\"" >> vc.h + echo >> vc.h + echo >> vc.h + +clean: + rm -f $(OBJECTS) $(BINDIR)/$(BINELF) $(BINDIR)/$(BINHEX) + +# Connect to openocd's gdb server on port 3333 +deploy: $(BINDIR)/$(BINELF) +ifeq ($(wildcard /opt/openocd/bin/openocd),) + /usr/bin/openocd -f /usr/share/openocd/scripts/board/stm32f4discovery.cfg -c "program bin/"$(BINELF)" verify reset" -c "init" -c "reset" -c "exit" +else + /opt/openocd/bin/openocd -f /opt/openocd/share/openocd/scripts/board/stm32f4discovery.cfg -c "program bin/"$(BINELF)" verify reset" -c "init" -c "reset" -c "exit" +endif + diff --git a/src/glutt-o-logique/audio.c b/src/glutt-o-logique/audio.c new file mode 100644 index 0000000..bdb2961 --- /dev/null +++ b/src/glutt-o-logique/audio.c @@ -0,0 +1,220 @@ +#include "GPIO/i2c.h" +#include "stm32f4xx_conf.h" +#include "stm32f4xx.h" + +#include "../../../common/src/Audio/audio.c" + +void audio_initialize_platform(int plln, int pllr, int i2sdiv, int i2sodd, int rate) { + + GPIO_InitTypeDef GPIO_InitStructure; + + // Turn on peripherals. + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); + RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE); + + // Assume I2C is set up + + // Configure reset pin. + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(GPIOD, &GPIO_InitStructure); + + // Configure I2S MCK, SCK, SD pins. + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_10 | GPIO_Pin_12; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(GPIOC, &GPIO_InitStructure); + + GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_SPI3); + GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_SPI3); + GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_SPI3); + + // Configure I2S WS pin. + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_SPI3); + + // Reset the codec. + GPIO_ResetBits(GPIOD, GPIO_Pin_4); + for (volatile int i = 0; i < 0x4fff; i++) { + __asm__ volatile("nop"); + } + GPIO_SetBits(GPIOD, GPIO_Pin_4); + + // Configure codec. + audio_write_register(0x02, 0x01); // Keep codec powered off. + audio_write_register(0x04, 0xaf); // SPK always off and HP always on. + + audio_write_register(0x05, 0x81); // Clock configuration: Auto detection. + audio_write_register(0x06, 0x04); // Set slave mode and Philips audio standard. + + // Power on the codec. + audio_write_register(0x02, 0x9e); + + // Configure codec for fast shutdown. + audio_write_register(0x0a, 0x00); // Disable the analog soft ramp. + audio_write_register(0x0e, 0x04); // Disable the digital soft ramp. + + audio_write_register(0x27, 0x00); // Disable the limiter attack level. + audio_write_register(0x1f, 0x0f); // Adjust bass and treble levels. + + audio_write_register(0x1a, 0x0a); // Adjust PCM volume level. + audio_write_register(0x1b, 0x0a); + + // Disable I2S. + SPI3 ->I2SCFGR = 0; + + // I2S clock configuration + RCC ->CFGR &= ~RCC_CFGR_I2SSRC; // PLLI2S clock used as I2S clock source. + RCC ->PLLI2SCFGR = (pllr << 28) | (plln << 6); + + // Enable PLLI2S and wait until it is ready. + RCC ->CR |= RCC_CR_PLLI2SON; + while (!(RCC ->CR & RCC_CR_PLLI2SRDY )) + ; + + // Configure I2S. + SPI3 ->I2SPR = i2sdiv | (i2sodd << 8) | SPI_I2SPR_MCKOE; + SPI3 ->I2SCFGR = SPI_I2SCFGR_I2SMOD | SPI_I2SCFGR_I2SCFG_1 + | SPI_I2SCFGR_I2SE; // Master transmitter, Phillips mode, 16 bit values, clock polarity low, enable. + +} + +void audio_on() { + audio_write_register(0x02, 0x9e); + SPI3 ->I2SCFGR = SPI_I2SCFGR_I2SMOD | SPI_I2SCFGR_I2SCFG_1 + | SPI_I2SCFGR_I2SE; // Master transmitter, Phillips mode, 16 bit values, clock polarity low, enable. +} + +void audio_off() { + audio_write_register(0x02, 0x9f); + SPI3 ->I2SCFGR = 0; +} + +void audio_set_volume(int volume) { + audio_write_register(0x20, (volume + 0x19) & 0xff); + audio_write_register(0x21, (volume + 0x19) & 0xff); +} + +void audio_output_sample(int16_t sample) { + while (!(SPI3 ->SR & SPI_SR_TXE )) + ; + SPI3 ->DR = sample; +} + + +void audio_output_sample_without_blocking(int16_t sample) { + SPI3 ->DR = sample; +} + +void audio_play_with_callback(AudioCallbackFunction *callback, void *context) { + audio_stop_dma(); + + NVIC_EnableIRQ(DMA1_Stream7_IRQn); + NVIC_SetPriority(DMA1_Stream7_IRQn, 5); + + SPI3 ->CR2 |= SPI_CR2_TXDMAEN; // Enable I2S TX DMA request. + + callback_function = callback; + callback_context = context; + buffer_number = 0; + + if (callback_function) + callback_function(callback_context, buffer_number); +} + +void audio_stop() { + audio_stop_dma(); + SPI3 ->CR2 &= ~SPI_CR2_TXDMAEN; // Disable I2S TX DMA request. + NVIC_DisableIRQ(DMA1_Stream7_IRQn); + callback_function = NULL; +} + +void audio_provide_buffer(void *samples, int numsamples) { + while (!audio_provide_buffer_without_blocking(samples, numsamples)) + __asm__ volatile ("wfi"); +} + +bool audio_provide_buffer_without_blocking(void *samples, int numsamples) { + if (next_buffer_samples) + return false; + + NVIC_DisableIRQ(DMA1_Stream7_IRQn); + + next_buffer_samples = samples; + next_buffer_length = numsamples; + + if (!dma_running) + audio_start_dma_and_request_buffers(); + + NVIC_EnableIRQ(DMA1_Stream7_IRQn); + + return true; +} + +static void audio_start_dma_and_request_buffers() { + // Configure DMA stream. + DMA1_Stream7 ->CR = (0 * DMA_SxCR_CHSEL_0 ) | // Channel 0 + (1 * DMA_SxCR_PL_0 ) | // Priority 1 + (1 * DMA_SxCR_PSIZE_0 ) | // PSIZE = 16 bit + (1 * DMA_SxCR_MSIZE_0 ) | // MSIZE = 16 bit + DMA_SxCR_MINC | // Increase memory address + (1 * DMA_SxCR_DIR_0 ) | // Memory to peripheral + DMA_SxCR_TCIE; // Transfer complete interrupt + DMA1_Stream7 ->NDTR = next_buffer_length; + DMA1_Stream7 ->PAR = (uint32_t) &SPI3 ->DR; + DMA1_Stream7 ->M0AR = (uint32_t) next_buffer_samples; + DMA1_Stream7 ->FCR = DMA_SxFCR_DMDIS; + DMA1_Stream7 ->CR |= DMA_SxCR_EN; + + // Update state. + next_buffer_samples = NULL; + buffer_number ^= 1; + dma_running = true; + + // Invoke callback if it exists to queue up another buffer. + if (callback_function) + callback_function(callback_context, buffer_number); +} + +static void audio_stop_dma() { + DMA1_Stream7 ->CR &= ~DMA_SxCR_EN; // Disable DMA stream. + while (DMA1_Stream7 ->CR & DMA_SxCR_EN ) + ; // Wait for DMA stream to stop. + + dma_running = false; +} + +void DMA1_Stream7_IRQHandler() { + DMA1 ->HIFCR |= DMA_HIFCR_CTCIF7; // Clear interrupt flag. + + if (next_buffer_samples) { + audio_start_dma_and_request_buffers(); + } else { + dma_running = false; + } +} + +// Warning: don't i2c_write call from IRQ handler ! +static void audio_write_register(uint8_t address, uint8_t value) +{ + const uint8_t device = 0x4a; + const uint8_t data[2] = {address, value}; + i2c_transaction_start(); + i2c_write(device, data, 2); + i2c_transaction_end(); +} + diff --git a/src/glutt-o-logique/common.c b/src/glutt-o-logique/common.c new file mode 100644 index 0000000..a647d26 --- /dev/null +++ b/src/glutt-o-logique/common.c @@ -0,0 +1,7 @@ +#include <stm32f4xx.h> + +#include "../../../common/src/Core/common.c" + +void hard_fault_handler_extra() { + usart_debug("SCB_SHCSR = %x\n", SCB->SHCSR); +} diff --git a/src/glutt-o-logique/cw.c b/src/glutt-o-logique/cw.c new file mode 100644 index 0000000..028ae82 --- /dev/null +++ b/src/glutt-o-logique/cw.c @@ -0,0 +1,4 @@ +#include "../../../common/src/Audio/cw.c" + +void cw_message_sent(const char* str) { +} diff --git a/src/glutt-o-logique/debug.c b/src/glutt-o-logique/debug.c new file mode 100644 index 0000000..2e33a32 --- /dev/null +++ b/src/glutt-o-logique/debug.c @@ -0,0 +1,77 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015 Matthias P. Braendli + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. +*/ + +#include <stddef.h> +#include <stdint.h> + +#include "debug.h" + +#if _DEBUG + +void debug_send_command(int command, void *message) +{ + __asm__ volatile ( + "mov r0, %[cmd];" + "mov r1, %[msg];" + "bkpt #0xAB" + : + : [cmd] "r" (command), [msg] "r" (message) + : "r0", "r1", "memory"); +} + +void put_char(char c) +{ + __asm__ volatile ( + "mov r0, #0x03\n" /* SYS_WRITEC */ + "mov r1, %[msg]\n" + "bkpt #0xAB\n" + : + : [msg] "r" (&c) + : "r0", "r1" + ); +} + +void debug_print(const char* str) +{ + const int std_err = 2; + + int strlen = 0; + const char* s; + s = str; + while (*s) { + strlen++; + s++; + } + + uint32_t m[] = { std_err, (uint32_t)str, strlen }; + debug_send_command(0x05, m); +} + +#else +void debug_send_command(int command, void *message) { } +void put_char(char c) { } +void debug_print(const char* str) { } + +#endif + diff --git a/src/glutt-o-logique/debug.h b/src/glutt-o-logique/debug.h new file mode 100644 index 0000000..6215e5f --- /dev/null +++ b/src/glutt-o-logique/debug.h @@ -0,0 +1,47 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015 Matthias P. Braendli + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. +*/ + +/* Debugging utilities using the ARM semihosting facilities. Warning, it's quite + * slow. + * + * when used with OpenOCD's gdb server, requires the gdb command + * + * monitor arm semihosting enable + */ +#ifndef __DEBUG_H_ +#define __DEBUG_H_ + +/* Example usage for the send_command function +const char *s = "Hello world\n"; +uint32_t m[] = { 2, (uint32_t)s, sizeof(s)/sizeof(char) }; +send_command(0x05, m); +// some interrupt ID + +*/ + +/* Print a string to the OpenOCD console */ +void debug_print(const char* str); + +#endif // __DEBUG_H_ + diff --git a/src/glutt-o-logique/delay.c b/src/glutt-o-logique/delay.c new file mode 100644 index 0000000..af959f7 --- /dev/null +++ b/src/glutt-o-logique/delay.c @@ -0,0 +1,51 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2016 Matthias P. Braendli, Maximilien Cuony + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. +*/ + +#include "Core/delay.h" +#include "stm32f4xx_conf.h" +#include "stm32f4xx.h" + +uint32_t delay_multiplier = 1; + +void delay_us(uint32_t micros) +{ + micros = micros * delay_multiplier - 10; + while (micros--); +} + +void delay_ms(uint32_t millis) +{ + for (int i = 0; i < 1000; i++) { + delay_us(millis); + } +} + +void delay_init() +{ + RCC_ClocksTypeDef RCC_Clocks; + RCC_GetClocksFreq(&RCC_Clocks); + + delay_multiplier = RCC_Clocks.HCLK_Frequency / 4000000; +} + diff --git a/src/glutt-o-logique/ds18b20/README b/src/glutt-o-logique/ds18b20/README new file mode 100644 index 0000000..0cd66d5 --- /dev/null +++ b/src/glutt-o-logique/ds18b20/README @@ -0,0 +1 @@ +This folder contains a library to access Dallas 1-wire temperature sensors. diff --git a/src/glutt-o-logique/ds18b20/tm_stm32f4_ds18b20.c b/src/glutt-o-logique/ds18b20/tm_stm32f4_ds18b20.c new file mode 100644 index 0000000..d16e48c --- /dev/null +++ b/src/glutt-o-logique/ds18b20/tm_stm32f4_ds18b20.c @@ -0,0 +1,394 @@ +/**
+ * |----------------------------------------------------------------------
+ * | Copyright (C) Tilen Majerle, 2014
+ * |
+ * | 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 3 of the License, or
+ * | 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, see <http://www.gnu.org/licenses/>.
+ * |----------------------------------------------------------------------
+ */
+#include "tm_stm32f4_ds18b20.h"
+
+uint8_t TM_DS18B20_Start(TM_OneWire_t* OneWire, uint8_t *ROM) {
+ /* Check if device is DS18B20 */
+ if (!TM_DS18B20_Is(ROM)) {
+ return 0;
+ }
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Start temperature conversion */
+ TM_OneWire_WriteByte(OneWire, DS18B20_CMD_CONVERTTEMP);
+
+ return 1;
+}
+
+void TM_DS18B20_StartAll(TM_OneWire_t* OneWire) {
+ /* Reset pulse */
+ TM_OneWire_Reset(OneWire);
+ /* Skip rom */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_SKIPROM);
+ /* Start conversion on all connected devices */
+ TM_OneWire_WriteByte(OneWire, DS18B20_CMD_CONVERTTEMP);
+}
+
+uint8_t TM_DS18B20_Read(TM_OneWire_t* OneWire, uint8_t *ROM, float *destination) {
+ uint16_t temperature;
+ uint8_t resolution;
+ int8_t digit, minus = 0;
+ float decimal;
+ uint8_t i = 0;
+ uint8_t data[9];
+ uint8_t crc;
+
+ /* Check if device is DS18B20 */
+ if (!TM_DS18B20_Is(ROM)) {
+ return 0;
+ }
+
+ /* Check if line is released, if it is, then conversion is complete */
+ if (!TM_OneWire_ReadBit(OneWire)) {
+ /* Conversion is not finished yet */
+ return 0;
+ }
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Read scratchpad command by onewire protocol */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_RSCRATCHPAD);
+
+ /* Get data */
+ for (i = 0; i < 9; i++) {
+ /* Read byte by byte */
+ data[i] = TM_OneWire_ReadByte(OneWire);
+ }
+
+ /* Calculate CRC */
+ crc = TM_OneWire_CRC8(data, 8);
+
+ /* Check if CRC is ok */
+ if (crc != data[8]) {
+ /* CRC invalid */
+ return 0;
+ }
+
+ /* First two bytes of scratchpad are temperature values */
+ temperature = data[0] | (data[1] << 8);
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+
+ /* Check if temperature is negative */
+ if (temperature & 0x8000) {
+ /* Two's complement, temperature is negative */
+ temperature = ~temperature + 1;
+ minus = 1;
+ }
+
+
+ /* Get sensor resolution */
+ resolution = ((data[4] & 0x60) >> 5) + 9;
+
+
+ /* Store temperature integer digits and decimal digits */
+ digit = temperature >> 4;
+ digit |= ((temperature >> 8) & 0x7) << 4;
+
+ /* Store decimal digits */
+ switch (resolution) {
+ case 9: {
+ decimal = (temperature >> 3) & 0x01;
+ decimal *= (float)DS18B20_DECIMAL_STEPS_9BIT;
+ } break;
+ case 10: {
+ decimal = (temperature >> 2) & 0x03;
+ decimal *= (float)DS18B20_DECIMAL_STEPS_10BIT;
+ } break;
+ case 11: {
+ decimal = (temperature >> 1) & 0x07;
+ decimal *= (float)DS18B20_DECIMAL_STEPS_11BIT;
+ } break;
+ case 12: {
+ decimal = temperature & 0x0F;
+ decimal *= (float)DS18B20_DECIMAL_STEPS_12BIT;
+ } break;
+ default: {
+ decimal = 0xFF;
+ digit = 0;
+ }
+ }
+
+ /* Check for negative part */
+ decimal = digit + decimal;
+ if (minus) {
+ decimal = 0 - decimal;
+ }
+
+ /* Set to pointer */
+ *destination = decimal;
+
+ /* Return 1, temperature valid */
+ return 1;
+}
+
+uint8_t TM_DS18B20_GetResolution(TM_OneWire_t* OneWire, uint8_t *ROM) {
+ uint8_t conf;
+
+ if (!TM_DS18B20_Is(ROM)) {
+ return 0;
+ }
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Read scratchpad command by onewire protocol */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_RSCRATCHPAD);
+
+ /* Ignore first 4 bytes */
+ TM_OneWire_ReadByte(OneWire);
+ TM_OneWire_ReadByte(OneWire);
+ TM_OneWire_ReadByte(OneWire);
+ TM_OneWire_ReadByte(OneWire);
+
+ /* 5th byte of scratchpad is configuration register */
+ conf = TM_OneWire_ReadByte(OneWire);
+
+ /* Return 9 - 12 value according to number of bits */
+ return ((conf & 0x60) >> 5) + 9;
+}
+
+uint8_t TM_DS18B20_SetResolution(TM_OneWire_t* OneWire, uint8_t *ROM, TM_DS18B20_Resolution_t resolution) {
+ uint8_t th, tl, conf;
+ if (!TM_DS18B20_Is(ROM)) {
+ return 0;
+ }
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Read scratchpad command by onewire protocol */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_RSCRATCHPAD);
+
+ /* Ignore first 2 bytes */
+ TM_OneWire_ReadByte(OneWire);
+ TM_OneWire_ReadByte(OneWire);
+
+ th = TM_OneWire_ReadByte(OneWire);
+ tl = TM_OneWire_ReadByte(OneWire);
+ conf = TM_OneWire_ReadByte(OneWire);
+
+ if (resolution == TM_DS18B20_Resolution_9bits) {
+ conf &= ~(1 << DS18B20_RESOLUTION_R1);
+ conf &= ~(1 << DS18B20_RESOLUTION_R0);
+ } else if (resolution == TM_DS18B20_Resolution_10bits) {
+ conf &= ~(1 << DS18B20_RESOLUTION_R1);
+ conf |= 1 << DS18B20_RESOLUTION_R0;
+ } else if (resolution == TM_DS18B20_Resolution_11bits) {
+ conf |= 1 << DS18B20_RESOLUTION_R1;
+ conf &= ~(1 << DS18B20_RESOLUTION_R0);
+ } else if (resolution == TM_DS18B20_Resolution_12bits) {
+ conf |= 1 << DS18B20_RESOLUTION_R1;
+ conf |= 1 << DS18B20_RESOLUTION_R0;
+ }
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Write scratchpad command by onewire protocol, only th, tl and conf register can be written */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_WSCRATCHPAD);
+
+ /* Write bytes */
+ TM_OneWire_WriteByte(OneWire, th);
+ TM_OneWire_WriteByte(OneWire, tl);
+ TM_OneWire_WriteByte(OneWire, conf);
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Copy scratchpad to EEPROM of DS18B20 */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_CPYSCRATCHPAD);
+
+ return 1;
+}
+
+uint8_t TM_DS18B20_Is(uint8_t *ROM) {
+ /* Checks if first byte is equal to DS18B20's family code */
+ if (*ROM == DS18B20_FAMILY_CODE) {
+ return 1;
+ }
+ return 0;
+}
+
+uint8_t TM_DS18B20_SetAlarmLowTemperature(TM_OneWire_t* OneWire, uint8_t *ROM, int8_t temp) {
+ uint8_t tl, th, conf;
+ if (!TM_DS18B20_Is(ROM)) {
+ return 0;
+ }
+ if (temp > 125) {
+ temp = 125;
+ }
+ if (temp < -55) {
+ temp = -55;
+ }
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Read scratchpad command by onewire protocol */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_RSCRATCHPAD);
+
+ /* Ignore first 2 bytes */
+ TM_OneWire_ReadByte(OneWire);
+ TM_OneWire_ReadByte(OneWire);
+
+ th = TM_OneWire_ReadByte(OneWire);
+ tl = TM_OneWire_ReadByte(OneWire);
+ conf = TM_OneWire_ReadByte(OneWire);
+
+ tl = (uint8_t)temp;
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Write scratchpad command by onewire protocol, only th, tl and conf register can be written */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_WSCRATCHPAD);
+
+ /* Write bytes */
+ TM_OneWire_WriteByte(OneWire, th);
+ TM_OneWire_WriteByte(OneWire, tl);
+ TM_OneWire_WriteByte(OneWire, conf);
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Copy scratchpad to EEPROM of DS18B20 */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_CPYSCRATCHPAD);
+
+ return 1;
+}
+
+uint8_t TM_DS18B20_SetAlarmHighTemperature(TM_OneWire_t* OneWire, uint8_t *ROM, int8_t temp) {
+ uint8_t tl, th, conf;
+ if (!TM_DS18B20_Is(ROM)) {
+ return 0;
+ }
+ if (temp > 125) {
+ temp = 125;
+ }
+ if (temp < -55) {
+ temp = -55;
+ }
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Read scratchpad command by onewire protocol */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_RSCRATCHPAD);
+
+ /* Ignore first 2 bytes */
+ TM_OneWire_ReadByte(OneWire);
+ TM_OneWire_ReadByte(OneWire);
+
+ th = TM_OneWire_ReadByte(OneWire);
+ tl = TM_OneWire_ReadByte(OneWire);
+ conf = TM_OneWire_ReadByte(OneWire);
+
+ th = (uint8_t)temp;
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Write scratchpad command by onewire protocol, only th, tl and conf register can be written */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_WSCRATCHPAD);
+
+ /* Write bytes */
+ TM_OneWire_WriteByte(OneWire, th);
+ TM_OneWire_WriteByte(OneWire, tl);
+ TM_OneWire_WriteByte(OneWire, conf);
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Copy scratchpad to EEPROM of DS18B20 */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_CPYSCRATCHPAD);
+
+ return 1;
+}
+
+uint8_t TM_DS18B20_DisableAlarmTemperature(TM_OneWire_t* OneWire, uint8_t *ROM) {
+ uint8_t tl, th, conf;
+ if (!TM_DS18B20_Is(ROM)) {
+ return 0;
+ }
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Read scratchpad command by onewire protocol */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_RSCRATCHPAD);
+
+ /* Ignore first 2 bytes */
+ TM_OneWire_ReadByte(OneWire);
+ TM_OneWire_ReadByte(OneWire);
+
+ th = TM_OneWire_ReadByte(OneWire);
+ tl = TM_OneWire_ReadByte(OneWire);
+ conf = TM_OneWire_ReadByte(OneWire);
+
+ th = 125;
+ tl = (uint8_t)-55;
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Write scratchpad command by onewire protocol, only th, tl and conf register can be written */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_WSCRATCHPAD);
+
+ /* Write bytes */
+ TM_OneWire_WriteByte(OneWire, th);
+ TM_OneWire_WriteByte(OneWire, tl);
+ TM_OneWire_WriteByte(OneWire, conf);
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Copy scratchpad to EEPROM of DS18B20 */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_CPYSCRATCHPAD);
+
+ return 1;
+}
+
+uint8_t TM_DS18B20_AlarmSearch(TM_OneWire_t* OneWire) {
+ /* Start alarm search */
+ return TM_OneWire_Search(OneWire, DS18B20_CMD_ALARMSEARCH);
+}
+
+uint8_t TM_DS18B20_AllDone(TM_OneWire_t* OneWire) {
+ /* If read bit is low, then device is not finished yet with calculation temperature */
+ return TM_OneWire_ReadBit(OneWire);
+}
+
+
diff --git a/src/glutt-o-logique/ds18b20/tm_stm32f4_ds18b20.h b/src/glutt-o-logique/ds18b20/tm_stm32f4_ds18b20.h new file mode 100644 index 0000000..337883e --- /dev/null +++ b/src/glutt-o-logique/ds18b20/tm_stm32f4_ds18b20.h @@ -0,0 +1,317 @@ +/**
+ * @author Tilen Majerle
+ * @email tilen@majerle.eu
+ * @website http://stm32f4-discovery.com
+ * @link http://stm32f4-discovery.com/2014/05/13-reading-temperature-with-dallas-ds18b20-on-stm32f429-discovery-board/
+ * @version v2.0
+ * @ide Keil uVision
+ * @license GNU GPL v3
+ * @brief Library for interfacing DS18B20 temperature sensor from Dallas semiconductors.
+ *
+@verbatim
+ ----------------------------------------------------------------------
+ Copyright (C) Tilen Majerle, 2015
+
+ 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 3 of the License, or
+ 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, see <http://www.gnu.org/licenses/>.
+ ----------------------------------------------------------------------
+@endverbatim
+ */
+/**
+ * Library for interfacing DS18B20 temperature sensor from Dallas semiconductors.
+ *
+ * @author Tilen Majerle
+ * @email tilen@majerle.eu
+ * @website http://stm32f4-discovery.com
+ * @link http://stm32f4-discovery.com/2014/05/13-reading-temperature-with-dallas-ds18b20-on-stm32f429-discovery-board/
+ * @version v2.0
+ * @ide Keil uVision
+ * @license GNU GPL v3
+ *
+ * |----------------------------------------------------------------------
+ * | Copyright (C) Tilen Majerle, 2014
+ * |
+ * | 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 3 of the License, or
+ * | 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, see <http://www.gnu.org/licenses/>.
+ * |----------------------------------------------------------------------
+ *
+ * Version 2.0
+ * - January 04, 2015
+ * - New system, supporting OneWire library 2.0
+ *
+ * Version 1.1
+ * - December 06, 2014
+ * - Now CRC is calculated and checked if data are valid
+ * - New version of OneWire library is required, download already available on stm32f4-discovery.com
+ *
+ * With this you can read temperature, set and get temperature resolution from 9 to 12 bits
+ * and check if device is DS18B20
+ *
+ * Pin for STM32F4xx is the same as set with TM ONEWIRE library.
+ */
+#ifndef TM_DS18B20_H
+#define TM_DS18B20_H 200
+
+/**
+ * @addtogroup TM_STM32F4xx_Libraries
+ * @{
+ */
+
+/**
+ * @defgroup TM_DS12820
+ * @brief Library for interfacing DS18B20 temperature sensor from Dallas semiconductors - http://stm32f4-discovery.com/2014/05/13-reading-temperature-with-dallas-ds18b20-on-stm32f429-discovery-board/
+ * @{
+ *
+ * With this you can read temperature, set and get temperature resolution from 9 to 12 bits and check if device is DS18B20.
+ *
+ * Pin for STM32F4xx is the same as set with TM ONEWIRE library.
+ *
+ * \par Changelog
+ *
+@verbatim
+ Version 2.0
+ - January 04, 2015
+ - New system, supporting OneWire library 2.0
+
+ Version 1.1
+ - December 06, 2014
+ - Now CRC is calculated and checked if data are valid
+ - New version of OneWire library is required, download already available on stm32f4-discovery.com
+
+ Version 1.0
+ - First release
+@endverbatim
+ *
+ * \par Dependencies
+ *
+@verbatim
+ - STM32F4xx
+ - TM ONEWIRE
+ - TM GPIO
+@endverbatim
+ */
+
+#include "stm32f4xx.h"
+#include "tm_stm32f4_onewire.h"
+
+/* OneWire version check */
+#if TM_ONEWIRE_H < 200
+#error "Please update TM ONEWIRE LIB, minimum required version is 2.0.0. Download available on stm32f4-discovery.com website"
+#endif
+
+/**
+ * @defgroup TM_DS18B20_Macros
+ * @brief Library defines
+ * @{
+ */
+
+/* Every onewire chip has different ROM code, but all the same chips has same family code */
+/* in case of DS18B20 this is 0x28 and this is first byte of ROM address */
+#define DS18B20_FAMILY_CODE 0x28
+#define DS18B20_CMD_ALARMSEARCH 0xEC
+
+/* DS18B20 read temperature command */
+#define DS18B20_CMD_CONVERTTEMP 0x44 /* Convert temperature */
+#define DS18B20_DECIMAL_STEPS_12BIT 0.0625
+#define DS18B20_DECIMAL_STEPS_11BIT 0.125
+#define DS18B20_DECIMAL_STEPS_10BIT 0.25
+#define DS18B20_DECIMAL_STEPS_9BIT 0.5
+
+/* Bits locations for resolution */
+#define DS18B20_RESOLUTION_R1 6
+#define DS18B20_RESOLUTION_R0 5
+
+/* CRC enabled */
+#ifdef DS18B20_USE_CRC
+#define DS18B20_DATA_LEN 9
+#else
+#define DS18B20_DATA_LEN 2
+#endif
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup TM_DS18B20_Typedefs
+ * @brief Library Typedefs
+ * @{
+ */
+
+/**
+ * @brief DS18B0 Resolutions available
+ */
+typedef enum {
+ TM_DS18B20_Resolution_9bits = 9, /*!< DS18B20 9 bits resolution */
+ TM_DS18B20_Resolution_10bits = 10, /*!< DS18B20 10 bits resolution */
+ TM_DS18B20_Resolution_11bits = 11, /*!< DS18B20 11 bits resolution */
+ TM_DS18B20_Resolution_12bits = 12 /*!< DS18B20 12 bits resolution */
+} TM_DS18B20_Resolution_t;
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup TM_DS18B20_Functions
+ * @brief Library Functions
+ * @{
+ */
+
+/**
+ * @brief Starts temperature conversion for specific DS18B20 on specific onewire channel
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel)
+ * @param *ROM: Pointer to first byte of ROM address for desired DS12B80 device.
+ * Entire ROM address is 8-bytes long
+ * @retval 1 if device is DS18B20 or 0 if not
+ */
+uint8_t TM_DS18B20_Start(TM_OneWire_t* OneWireStruct, uint8_t* ROM);
+
+/**
+ * @brief Starts temperature conversion for all DS18B20 devices on specific onewire channel
+ * @note This mode will skip ROM addressing
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel)
+ * @retval None
+ */
+void TM_DS18B20_StartAll(TM_OneWire_t* OneWireStruct);
+
+/**
+ * @brief Reads temperature from DS18B20
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel)
+ * @param *ROM: Pointer to first byte of ROM address for desired DS12B80 device.
+ * Entire ROM address is 8-bytes long
+ * @param *destination: Pointer to float variable to store temperature
+ * @retval Temperature status:
+ * - 0: Device is not DS18B20 or conversion is not done yet or CRC failed
+ * - > 0: Temperature is read OK
+ */
+uint8_t TM_DS18B20_Read(TM_OneWire_t* OneWireStruct, uint8_t* ROM, float* destination);
+
+/**
+ * @brief Gets resolution for temperature conversion from DS18B20 device
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel)
+ * @param *ROM: Pointer to first byte of ROM address for desired DS12B80 device.
+ * Entire ROM address is 8-bytes long
+ * @retval Resolution:
+ * - 0: Device is not DS18B20
+ * - 9 - 12: Resolution of DS18B20
+ */
+uint8_t TM_DS18B20_GetResolution(TM_OneWire_t* OneWireStruct, uint8_t* ROM);
+
+/**
+ * @brief Sets resolution for specific DS18B20 device
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel)
+ * @param *ROM: Pointer to first byte of ROM address for desired DS12B80 device.
+ * Entire ROM address is 8-bytes long
+ * @param resolution: Resolution for DS18B20 device. This parameter can be a value of @ref TM_DS18B20_Resolution_t enumeration.
+ * @retval Success status:
+ * - 0: Device is not DS18B20
+ * - > 0: Resolution set OK
+ */
+uint8_t TM_DS18B20_SetResolution(TM_OneWire_t* OneWireStruct, uint8_t* ROM, TM_DS18B20_Resolution_t resolution);
+
+/**
+ * @brief Checks if device with specific ROM number is DS18B20
+ * @param *ROM: Pointer to first byte of ROM address for desired DS12B80 device.
+ * Entire ROM address is 8-bytes long
+ * @retval Device status
+ * - 0: Device is not DS18B20
+ * - > 0: Device is DS18B20
+ */
+uint8_t TM_DS18B20_Is(uint8_t* ROM);
+
+/**
+ * @brief Sets high alarm temperature to specific DS18B20 sensor
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel)
+ * @param *ROM: Pointer to first byte of ROM address for desired DS12B80 device.
+ * Entire ROM address is 8-bytes long
+ * @param temp: integer value for temperature between -55 to 125 degrees
+ * @retval Success status:
+ * - 0: Device is not DS18B20
+ * - > 0: High alarm set OK
+ */
+uint8_t TM_DS18B20_SetAlarmHighTemperature(TM_OneWire_t* OneWireStruct, uint8_t* ROM, int8_t temp);
+
+/**
+ * @brief Sets low alarm temperature to specific DS18B20 sensor
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel)
+ * @param *ROM: Pointer to first byte of ROM address for desired DS12B80 device.
+ * Entire ROM address is 8-bytes long
+ * @param temp: integer value for temperature between -55 to 125 degrees
+ * @retval Success status:
+ * - 0: Device is not DS18B20
+ * - > 0: Low alarm set OK
+ */
+uint8_t TM_DS18B20_SetAlarmLowTemperature(TM_OneWire_t* OneWireStruct, uint8_t* ROM, int8_t temp);
+
+/**
+ * @brief Disables alarm temperature for specific DS18B20 sensor
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel)
+ * @param *ROM: Pointer to first byte of ROM address for desired DS12B80 device.
+ * Entire ROM address is 8-bytes long
+ * @retval Success status:
+ * - 0: Device is not DS18B20
+ * - > 0: Alarm disabled OK
+ */
+uint8_t TM_DS18B20_DisableAlarmTemperature(TM_OneWire_t* OneWireStruct, uint8_t* ROM);
+
+/**
+ * @brief Searches for devices with alarm flag set
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel)
+ * @retval Alarm search status
+ * - 0: No device found with alarm flag set
+ * - > 0: Device is found with alarm flag
+ * @note To get all devices on one onewire channel with alarm flag set, you can do this:
+@verbatim
+while (TM_DS18B20_AlarmSearch(&OneWireStruct)) {
+ //Read device ID here
+ //Print to user device by device
+}
+@endverbatim
+ * @retval 1 if any device has flag, otherwise 0
+ */
+uint8_t TM_DS18B20_AlarmSearch(TM_OneWire_t* OneWireStruct);
+
+/**
+ * @brief Checks if all DS18B20 sensors are done with temperature conversion
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel)
+ * @retval Conversion status
+ * - 0: Not all devices are done
+ * - > 0: All devices are done with conversion
+ */
+uint8_t TM_DS18B20_AllDone(TM_OneWire_t* OneWireStruct);
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif
+
diff --git a/src/glutt-o-logique/ds18b20/tm_stm32f4_onewire.c b/src/glutt-o-logique/ds18b20/tm_stm32f4_onewire.c new file mode 100644 index 0000000..44ec8db --- /dev/null +++ b/src/glutt-o-logique/ds18b20/tm_stm32f4_onewire.c @@ -0,0 +1,414 @@ +/**
+ * |----------------------------------------------------------------------
+ * | Copyright (C) Tilen Majerle, 2014
+ * |
+ * | 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 3 of the License, or
+ * | 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, see <http://www.gnu.org/licenses/>.
+ * |----------------------------------------------------------------------
+ */
+#include "tm_stm32f4_onewire.h"
+
+void delay_us(uint32_t);
+
+static void
+TM_GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
+{
+ GPIO_SetBits(GPIOx, GPIO_Pin);
+}
+
+static void
+TM_GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
+{
+ GPIO_ResetBits(GPIOx, GPIO_Pin);
+}
+
+
+static void
+TM_GPIO_SetPinAsInput(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
+{
+ GPIO_SetBits(GPIOx, GPIO_Pin);
+}
+
+static void
+TM_GPIO_SetPinAsOutput(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
+{
+#if 0
+ GPIO_InitTypeDef GPIO_InitStructure;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
+ GPIO_InitStructure.GPIO_Pin = GPIO_Pin;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
+ GPIO_Init(GPIOx, &GPIO_InitStructure);
+#endif
+ GPIO_ResetBits(GPIOx, GPIO_Pin);
+}
+
+static int
+TM_GPIO_GetInputPinValue(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
+{
+ return GPIO_ReadInputDataBit(GPIOx, GPIO_Pin) ? 1 : 0;
+}
+
+static void
+ONEWIRE_DELAY(uint32_t micros)
+{
+ delay_us(micros);
+}
+
+void TM_OneWire_Init(TM_OneWire_t* OneWireStruct, GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) {
+ ONEWIRE_INPUT(OneWireStruct);
+ /* Save settings */
+ OneWireStruct->GPIOx = GPIOx;
+ OneWireStruct->GPIO_Pin = GPIO_Pin;
+}
+
+uint8_t TM_OneWire_Reset(TM_OneWire_t* OneWireStruct) {
+ uint8_t i;
+
+ /* Line low, and wait 480us */
+ ONEWIRE_LOW(OneWireStruct);
+ ONEWIRE_OUTPUT(OneWireStruct);
+ ONEWIRE_DELAY(480);
+
+ /* Release line and wait for 70us */
+ ONEWIRE_INPUT(OneWireStruct);
+ ONEWIRE_DELAY(70);
+
+ /* Check bit value */
+ i = TM_GPIO_GetInputPinValue(OneWireStruct->GPIOx, OneWireStruct->GPIO_Pin);
+
+ /* Delay for 410 us */
+ ONEWIRE_DELAY(410);
+
+ /* Return value of presence pulse, 0 = OK, 1 = ERROR */
+ return i;
+}
+
+void TM_OneWire_WriteBit(TM_OneWire_t* OneWireStruct, uint8_t bit) {
+ if (bit) {
+ /* Set line low */
+ ONEWIRE_LOW(OneWireStruct);
+ ONEWIRE_OUTPUT(OneWireStruct);
+ ONEWIRE_DELAY(10);
+
+ /* Bit high */
+ ONEWIRE_INPUT(OneWireStruct);
+
+ /* Wait for 55 us and release the line */
+ ONEWIRE_DELAY(55);
+ ONEWIRE_INPUT(OneWireStruct);
+ } else {
+ /* Set line low */
+ ONEWIRE_LOW(OneWireStruct);
+ ONEWIRE_OUTPUT(OneWireStruct);
+ ONEWIRE_DELAY(65);
+
+ /* Bit high */
+ ONEWIRE_INPUT(OneWireStruct);
+
+ /* Wait for 5 us and release the line */
+ ONEWIRE_DELAY(5);
+ ONEWIRE_INPUT(OneWireStruct);
+ }
+
+}
+
+uint8_t TM_OneWire_ReadBit(TM_OneWire_t* OneWireStruct) {
+ uint8_t bit = 0;
+
+ /* Line low */
+ ONEWIRE_LOW(OneWireStruct);
+ ONEWIRE_OUTPUT(OneWireStruct);
+ ONEWIRE_DELAY(3);
+
+ /* Release line */
+ ONEWIRE_INPUT(OneWireStruct);
+ ONEWIRE_DELAY(10);
+
+ /* Read line value */
+ if (TM_GPIO_GetInputPinValue(OneWireStruct->GPIOx, OneWireStruct->GPIO_Pin)) {
+ /* Bit is HIGH */
+ bit = 1;
+ }
+
+ /* Wait 50us to complete 60us period */
+ ONEWIRE_DELAY(50);
+
+ /* Return bit value */
+ return bit;
+}
+
+void TM_OneWire_WriteByte(TM_OneWire_t* OneWireStruct, uint8_t byte) {
+ uint8_t i = 8;
+ /* Write 8 bits */
+ while (i--) {
+ /* LSB bit is first */
+ TM_OneWire_WriteBit(OneWireStruct, byte & 0x01);
+ byte >>= 1;
+ }
+}
+
+uint8_t TM_OneWire_ReadByte(TM_OneWire_t* OneWireStruct) {
+ uint8_t i = 8, byte = 0;
+ while (i--) {
+ byte >>= 1;
+ byte |= (TM_OneWire_ReadBit(OneWireStruct) << 7);
+ }
+
+ return byte;
+}
+
+uint8_t TM_OneWire_First(TM_OneWire_t* OneWireStruct) {
+ /* Reset search values */
+ TM_OneWire_ResetSearch(OneWireStruct);
+
+ /* Start with searching */
+ return TM_OneWire_Search(OneWireStruct, ONEWIRE_CMD_SEARCHROM);
+}
+
+uint8_t TM_OneWire_Next(TM_OneWire_t* OneWireStruct) {
+ /* Leave the search state alone */
+ return TM_OneWire_Search(OneWireStruct, ONEWIRE_CMD_SEARCHROM);
+}
+
+void TM_OneWire_ResetSearch(TM_OneWire_t* OneWireStruct) {
+ /* Reset the search state */
+ OneWireStruct->LastDiscrepancy = 0;
+ OneWireStruct->LastDeviceFlag = 0;
+ OneWireStruct->LastFamilyDiscrepancy = 0;
+}
+
+uint8_t TM_OneWire_Search(TM_OneWire_t* OneWireStruct, uint8_t command) {
+ uint8_t id_bit_number;
+ uint8_t last_zero, rom_byte_number, search_result;
+ uint8_t id_bit, cmp_id_bit;
+ uint8_t rom_byte_mask, search_direction;
+
+ /* Initialize for search */
+ id_bit_number = 1;
+ last_zero = 0;
+ rom_byte_number = 0;
+ rom_byte_mask = 1;
+ search_result = 0;
+
+ // if the last call was not the last one
+ if (!OneWireStruct->LastDeviceFlag) {
+ // 1-Wire reset
+ if (TM_OneWire_Reset(OneWireStruct)) {
+ /* Reset the search */
+ OneWireStruct->LastDiscrepancy = 0;
+ OneWireStruct->LastDeviceFlag = 0;
+ OneWireStruct->LastFamilyDiscrepancy = 0;
+ return 0;
+ }
+
+ // issue the search command
+ TM_OneWire_WriteByte(OneWireStruct, command);
+
+ // loop to do the search
+ do {
+ // read a bit and its complement
+ id_bit = TM_OneWire_ReadBit(OneWireStruct);
+ cmp_id_bit = TM_OneWire_ReadBit(OneWireStruct);
+
+ // check for no devices on 1-wire
+ if ((id_bit == 1) && (cmp_id_bit == 1)) {
+ break;
+ } else {
+ // all devices coupled have 0 or 1
+ if (id_bit != cmp_id_bit) {
+ search_direction = id_bit; // bit write value for search
+ } else {
+ // if this discrepancy if before the Last Discrepancy
+ // on a previous next then pick the same as last time
+ if (id_bit_number < OneWireStruct->LastDiscrepancy) {
+ search_direction = ((OneWireStruct->ROM_NO[rom_byte_number] & rom_byte_mask) > 0);
+ } else {
+ // if equal to last pick 1, if not then pick 0
+ search_direction = (id_bit_number == OneWireStruct->LastDiscrepancy);
+ }
+
+ // if 0 was picked then record its position in LastZero
+ if (search_direction == 0) {
+ last_zero = id_bit_number;
+
+ // check for Last discrepancy in family
+ if (last_zero < 9) {
+ OneWireStruct->LastFamilyDiscrepancy = last_zero;
+ }
+ }
+ }
+
+ // set or clear the bit in the ROM byte rom_byte_number
+ // with mask rom_byte_mask
+ if (search_direction == 1) {
+ OneWireStruct->ROM_NO[rom_byte_number] |= rom_byte_mask;
+ } else {
+ OneWireStruct->ROM_NO[rom_byte_number] &= ~rom_byte_mask;
+ }
+
+ // serial number search direction write bit
+ TM_OneWire_WriteBit(OneWireStruct, search_direction);
+
+ // increment the byte counter id_bit_number
+ // and shift the mask rom_byte_mask
+ id_bit_number++;
+ rom_byte_mask <<= 1;
+
+ // if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask
+ if (rom_byte_mask == 0) {
+ //docrc8(ROM_NO[rom_byte_number]); // accumulate the CRC
+ rom_byte_number++;
+ rom_byte_mask = 1;
+ }
+ }
+ } while (rom_byte_number < 8); // loop until through all ROM bytes 0-7
+
+ // if the search was successful then
+ if (!(id_bit_number < 65)) {
+ // search successful so set LastDiscrepancy,LastDeviceFlag,search_result
+ OneWireStruct->LastDiscrepancy = last_zero;
+
+ // check for last device
+ if (OneWireStruct->LastDiscrepancy == 0) {
+ OneWireStruct->LastDeviceFlag = 1;
+ }
+
+ search_result = 1;
+ }
+ }
+
+ // if no device found then reset counters so next 'search' will be like a first
+ if (!search_result || !OneWireStruct->ROM_NO[0]) {
+ OneWireStruct->LastDiscrepancy = 0;
+ OneWireStruct->LastDeviceFlag = 0;
+ OneWireStruct->LastFamilyDiscrepancy = 0;
+ search_result = 0;
+ }
+
+ return search_result;
+}
+
+int TM_OneWire_Verify(TM_OneWire_t* OneWireStruct) {
+ unsigned char rom_backup[8];
+ int i,rslt,ld_backup,ldf_backup,lfd_backup;
+
+ // keep a backup copy of the current state
+ for (i = 0; i < 8; i++)
+ rom_backup[i] = OneWireStruct->ROM_NO[i];
+ ld_backup = OneWireStruct->LastDiscrepancy;
+ ldf_backup = OneWireStruct->LastDeviceFlag;
+ lfd_backup = OneWireStruct->LastFamilyDiscrepancy;
+
+ // set search to find the same device
+ OneWireStruct->LastDiscrepancy = 64;
+ OneWireStruct->LastDeviceFlag = 0;
+
+ if (TM_OneWire_Search(OneWireStruct, ONEWIRE_CMD_SEARCHROM)) {
+ // check if same device found
+ rslt = 1;
+ for (i = 0; i < 8; i++) {
+ if (rom_backup[i] != OneWireStruct->ROM_NO[i]) {
+ rslt = 1;
+ break;
+ }
+ }
+ } else {
+ rslt = 0;
+ }
+
+ // restore the search state
+ for (i = 0; i < 8; i++) {
+ OneWireStruct->ROM_NO[i] = rom_backup[i];
+ }
+ OneWireStruct->LastDiscrepancy = ld_backup;
+ OneWireStruct->LastDeviceFlag = ldf_backup;
+ OneWireStruct->LastFamilyDiscrepancy = lfd_backup;
+
+ // return the result of the verify
+ return rslt;
+}
+
+void TM_OneWire_TargetSetup(TM_OneWire_t* OneWireStruct, uint8_t family_code) {
+ uint8_t i;
+
+ // set the search state to find SearchFamily type devices
+ OneWireStruct->ROM_NO[0] = family_code;
+ for (i = 1; i < 8; i++) {
+ OneWireStruct->ROM_NO[i] = 0;
+ }
+
+ OneWireStruct->LastDiscrepancy = 64;
+ OneWireStruct->LastFamilyDiscrepancy = 0;
+ OneWireStruct->LastDeviceFlag = 0;
+}
+
+void TM_OneWire_FamilySkipSetup(TM_OneWire_t* OneWireStruct) {
+ // set the Last discrepancy to last family discrepancy
+ OneWireStruct->LastDiscrepancy = OneWireStruct->LastFamilyDiscrepancy;
+ OneWireStruct->LastFamilyDiscrepancy = 0;
+
+ // check for end of list
+ if (OneWireStruct->LastDiscrepancy == 0) {
+ OneWireStruct->LastDeviceFlag = 1;
+ }
+}
+
+uint8_t TM_OneWire_GetROM(TM_OneWire_t* OneWireStruct, uint8_t index) {
+ return OneWireStruct->ROM_NO[index];
+}
+
+void TM_OneWire_Select(TM_OneWire_t* OneWireStruct, uint8_t* addr) {
+ uint8_t i;
+ TM_OneWire_WriteByte(OneWireStruct, ONEWIRE_CMD_MATCHROM);
+
+ for (i = 0; i < 8; i++) {
+ TM_OneWire_WriteByte(OneWireStruct, *(addr + i));
+ }
+}
+
+void TM_OneWire_SelectWithPointer(TM_OneWire_t* OneWireStruct, uint8_t *ROM) {
+ uint8_t i;
+ TM_OneWire_WriteByte(OneWireStruct, ONEWIRE_CMD_MATCHROM);
+
+ for (i = 0; i < 8; i++) {
+ TM_OneWire_WriteByte(OneWireStruct, *(ROM + i));
+ }
+}
+
+void TM_OneWire_GetFullROM(TM_OneWire_t* OneWireStruct, uint8_t *firstIndex) {
+ uint8_t i;
+ for (i = 0; i < 8; i++) {
+ *(firstIndex + i) = OneWireStruct->ROM_NO[i];
+ }
+}
+
+uint8_t TM_OneWire_CRC8(uint8_t *addr, uint8_t len) {
+ uint8_t crc = 0, inbyte, i, mix;
+
+ while (len--) {
+ inbyte = *addr++;
+ for (i = 8; i; i--) {
+ mix = (crc ^ inbyte) & 0x01;
+ crc >>= 1;
+ if (mix) {
+ crc ^= 0x8C;
+ }
+ inbyte >>= 1;
+ }
+ }
+
+ /* Return calculated CRC */
+ return crc;
+}
diff --git a/src/glutt-o-logique/ds18b20/tm_stm32f4_onewire.h b/src/glutt-o-logique/ds18b20/tm_stm32f4_onewire.h new file mode 100644 index 0000000..9b14109 --- /dev/null +++ b/src/glutt-o-logique/ds18b20/tm_stm32f4_onewire.h @@ -0,0 +1,300 @@ +/**
+ * @author Tilen Majerle
+ * @email tilen@majerle.eu
+ * @website http://stm32f4-discovery.com
+ * @link http://stm32f4-discovery.com/2014/05/library-12-onewire-library-for-stm43f4xx/
+ * @version v2.1
+ * @ide Keil uVision
+ * @license GNU GPL v3
+ * @brief Onewire library for STM32F4 devices
+ *
+@verbatim
+ ----------------------------------------------------------------------
+ Copyright (C) Tilen Majerle, 2015
+
+ 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 3 of the License, or
+ 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, see <http://www.gnu.org/licenses/>.
+ ----------------------------------------------------------------------
+@endverbatim
+ */
+#ifndef TM_ONEWIRE_H
+#define TM_ONEWIRE_H 210
+
+/* C++ detection */
+#ifdef __cplusplus
+extern C {
+#endif
+
+/**
+ * @addtogroup TM_STM32F4xx_Libraries
+ * @{
+ */
+
+/**
+ * @defgroup TM_ONEWIRE
+ * @brief Onewire library for STM32F4 devices - http://stm32f4-discovery.com/2014/05/library-12-onewire-library-for-stm43f4xx/
+ * @{
+ *
+ * As of version 2.0 you can now use more than just one one-wire "port" on STM32F4. This allows you to group devices to separate ports.
+ *
+ * Because if you have a loot devices on one port, if one device fail, everything is failed. You can prevent this by use more than just one port.
+ *
+ * To set your port and pin for OneWire protocol, you can do this when calling @ref TM_OneWire_Init function.
+ *
+ * \par Changelog
+ *
+@verbatim
+ Version 2.1
+ - March 10, 2015
+ - Added support for new GPIO library
+
+ Version 2.0
+ - January 04, 2015
+ - New OneWire system
+ - With support for multiple OneWire ports to separate group of devices
+
+ Version 1.1
+ - December 06, 2014
+ - Added 8-bit CRC calculation for 1-Wire devices, algorithm from Dallas
+
+ Version 1.0
+ - First release
+@endverbatim
+ *
+ * \par Dependencies
+ *
+@verbatim
+ - STM32F4xx
+ - STM32F4xx RCC
+ - STM32F4xx GPIO
+ - TM GPIO
+@endverbatim
+ */
+#include "stm32f4xx.h"
+#include "stm32f4xx_rcc.h"
+#include "stm32f4xx_gpio.h"
+
+/**
+ * @defgroup TM_ONEWIRE_Macros
+ * @brief Library defines
+ * @{
+ */
+
+/* Pin settings */
+
+#define ONEWIRE_LOW(structure) TM_GPIO_ResetBits((structure)->GPIOx, (structure)->GPIO_Pin)
+#define ONEWIRE_HIGH(structure) TM_GPIO_SetBits((structure)->GPIOx, (structure)->GPIO_Pin)
+#define ONEWIRE_INPUT(structure) TM_GPIO_SetPinAsInput(structure->GPIOx, (structure)->GPIO_Pin)
+#define ONEWIRE_OUTPUT(structure) TM_GPIO_SetPinAsOutput(structure->GPIOx, (structure)->GPIO_Pin)
+
+/* OneWire commands */
+#define ONEWIRE_CMD_RSCRATCHPAD 0xBE
+#define ONEWIRE_CMD_WSCRATCHPAD 0x4E
+#define ONEWIRE_CMD_CPYSCRATCHPAD 0x48
+#define ONEWIRE_CMD_RECEEPROM 0xB8
+#define ONEWIRE_CMD_RPWRSUPPLY 0xB4
+#define ONEWIRE_CMD_SEARCHROM 0xF0
+#define ONEWIRE_CMD_READROM 0x33
+#define ONEWIRE_CMD_MATCHROM 0x55
+#define ONEWIRE_CMD_SKIPROM 0xCC
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup TM_ONEWIRE_Typedefs
+ * @brief Library Typedefs
+ * @{
+ */
+
+/**
+ * @brief OneWire working struct
+ * @note Except ROM_NO member, everything is fully private and should not be touched by user
+ */
+typedef struct {
+ GPIO_TypeDef* GPIOx; /*!< GPIOx port to be used for I/O functions */
+ uint16_t GPIO_Pin; /*!< GPIO Pin to be used for I/O functions */
+ uint8_t LastDiscrepancy; /*!< Search private */
+ uint8_t LastFamilyDiscrepancy; /*!< Search private */
+ uint8_t LastDeviceFlag; /*!< Search private */
+ uint8_t ROM_NO[8]; /*!< 8-bytes address of last search device */
+} TM_OneWire_t;
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup TM_ONEWIRE_Functions
+ * @brief Library Functions
+ * @{
+ */
+
+/**
+ * @brief Initializes OneWire bus
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t empty working onewire structure
+ * @param *Pointer to GPIO port used for onewire channel
+ * @param GPIO_Pin: GPIO Pin on specific GPIOx to be used for onewire channel
+ * @retval None
+ */
+void TM_OneWire_Init(TM_OneWire_t* OneWireStruct, GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
+
+/**
+ * @brief Resets OneWire bus
+ *
+ * @note Sends reset command for OneWire
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire structure
+ * @retval None
+ */
+uint8_t TM_OneWire_Reset(TM_OneWire_t* OneWireStruct);
+
+/**
+ * @brief Reads byte from one wire bus
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire structure
+ * @retval Byte from read operation
+ */
+uint8_t TM_OneWire_ReadByte(TM_OneWire_t* OneWireStruct);
+
+/**
+ * @brief Writes byte to bus
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire structure
+ * @param byte: 8-bit value to write over OneWire protocol
+ * @retval None
+ */
+void TM_OneWire_WriteByte(TM_OneWire_t* OneWireStruct, uint8_t byte);
+
+/**
+ * @brief Writes single bit to onewire bus
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire structure
+ * @param bit: Bit value to send, 1 or 0
+ * @retval None
+ */
+void TM_OneWire_WriteBit(TM_OneWire_t* OneWireStruct, uint8_t bit);
+
+/**
+ * @brief Reads single bit from one wire bus
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire structure
+ * @retval Bit value:
+ * - 0: Bit is low (zero)
+ * - > 0: Bit is high (one)
+ */
+uint8_t TM_OneWire_ReadBit(TM_OneWire_t* OneWireStruct);
+
+/**
+ * @brief Searches for OneWire devices on specific Onewire port
+ * @note Not meant for public use. Use @ref TM_OneWire_First and @ref TM_OneWire_Next for this.
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire structure where to search
+ * @param Device status:
+ * - 0: No devices detected
+ * - > 0: Device detected
+ */
+uint8_t TM_OneWire_Search(TM_OneWire_t* OneWireStruct, uint8_t command);
+
+/**
+ * @brief Resets search states
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire where to reset search values
+ * @retval None
+ */
+void TM_OneWire_ResetSearch(TM_OneWire_t* OneWireStruct);
+
+/**
+ * @brief Starts search, reset states first
+ * @note When you want to search for ALL devices on one onewire port, you should first use this function.
+@verbatim
+/...Initialization before
+status = TM_OneWire_First(&OneWireStruct);
+while (status) {
+ //Save ROM number from device
+ TM_OneWire_GetFullROM(ROM_Array_Pointer);
+ //Check for new device
+ status = TM_OneWire_Next(&OneWireStruct);
+}
+@endverbatim
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire where to reset search values
+ * @param Device status:
+ * - 0: No devices detected
+ * - > 0: Device detected
+ */
+uint8_t TM_OneWire_First(TM_OneWire_t* OneWireStruct);
+
+/**
+ * @brief Reads next device
+ * @note Use @ref TM_OneWire_First to start searching
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire
+ * @param Device status:
+ * - 0: No devices detected any more
+ * - > 0: New device detected
+ */
+uint8_t TM_OneWire_Next(TM_OneWire_t* OneWireStruct);
+
+/**
+ * @brief Gets ROM number from device from search
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire
+ * @param index: Because each device has 8-bytes long ROm address, you have to call this 8 times, to get ROM bytes from 0 to 7
+ * @reetval ROM byte for index (0 to 7) at current found device
+ */
+uint8_t TM_OneWire_GetROM(TM_OneWire_t* OneWireStruct, uint8_t index);
+
+/**
+ * @brief Gets all 8 bytes ROM value from device from search
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire
+ * @param *firstIndex: Pointer to first location for first byte, other bytes are automatically incremented
+ * @retval None
+ */
+void TM_OneWire_GetFullROM(TM_OneWire_t* OneWireStruct, uint8_t *firstIndex);
+
+/**
+ * @brief Selects specific slave on bus
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire
+ * @param *addr: Pointer to first location of 8-bytes long ROM address
+ * @retval None
+ */
+void TM_OneWire_Select(TM_OneWire_t* OneWireStruct, uint8_t* addr);
+
+/**
+ * @brief Selects specific slave on bus with pointer address
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire
+ * @param *ROM: Pointer to first byte of ROM address
+ * @retval None
+ */
+void TM_OneWire_SelectWithPointer(TM_OneWire_t* OneWireStruct, uint8_t* ROM);
+
+/**
+ * @brief Calculates 8-bit CRC for 1-wire devices
+ * @param *addr: Pointer to 8-bit array of data to calculate CRC
+ * @param len: Number of bytes to check
+ *
+ * @retval Calculated CRC from input data
+ */
+uint8_t TM_OneWire_CRC8(uint8_t* addr, uint8_t len);
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/* C++ detection */
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/glutt-o-logique/fsm.c b/src/glutt-o-logique/fsm.c new file mode 100644 index 0000000..99413ba --- /dev/null +++ b/src/glutt-o-logique/fsm.c @@ -0,0 +1,8 @@ +#include "../../../common/src/Core/fsm.c" + + +void fsm_state_switched(char * new_state) { + usart_debug_puts("FSM: "); + usart_debug_puts(new_state); + usart_debug_puts("\r\n"); +} diff --git a/src/glutt-o-logique/gps.c b/src/glutt-o-logique/gps.c new file mode 100644 index 0000000..10afe88 --- /dev/null +++ b/src/glutt-o-logique/gps.c @@ -0,0 +1,4 @@ +#include "stm32f4xx_conf.h" +#include "stm32f4xx.h" + +#include "../../../common/src/GPS/gps.c" diff --git a/src/glutt-o-logique/i2c.c b/src/glutt-o-logique/i2c.c new file mode 100644 index 0000000..750f5de --- /dev/null +++ b/src/glutt-o-logique/i2c.c @@ -0,0 +1,350 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015 Matthias P. Braendli + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. +*/ + +#include "GPIO/i2c.h" +#include "Core/common.h" + +#include "stm32f4xx_conf.h" +#include "stm32f4xx_i2c.h" +#include "stm32f4xx.h" +#include "FreeRTOS.h" +#include "FreeRTOSConfig.h" +#include "task.h" +#include "semphr.h" +#include "GPIO/usart.h" + +/* I2C 1 on PB9 and PB6 + * See pio.txt for PIO allocation details */ +const uint16_t GPIOB_PIN_SDA = GPIO_Pin_9; +const uint16_t GPIOB_PIN_SCL = GPIO_Pin_6; + + +static int i2c_init_done = 0; +static int i2c_error = 0; + +static I2C_TypeDef* const I2Cx = I2C1; + +static SemaphoreHandle_t i2c_semaphore; + +static void i2c_device_init(void); + +/* According to I2C spec UM10204: + * 3.1.16 Bus clear + * In the unlikely event where the clock (SCL) is stuck LOW, the preferential + * procedure is to reset the bus using the HW reset signal if your I2C devices + * have HW reset inputs. If the I2C devices do not have HW reset inputs, cycle + * power to the devices to activate the mandatory internal Power-On Reset (POR) + * circuit. + * + * If the data line (SDA) is stuck LOW, the master should send nine clock + * pulses. The device that held the bus LOW should release it sometime within + * those nine clocks. If not, then use the HW reset or cycle power to clear the + * bus. + */ +static void i2c_recover_from_lockup(void) +{ + usart_debug_puts("ERROR: I2C lockup\r\n"); + + I2C_SoftwareResetCmd(I2Cx, ENABLE); + + // Configure I2C SCL and SDA pins. + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.GPIO_Pin = GPIOB_PIN_SCL | GPIOB_PIN_SDA; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_Init(GPIOB, &GPIO_InitStructure); + + const TickType_t delay = 5 / portTICK_PERIOD_MS; + + GPIO_SetBits(GPIOB, GPIOB_PIN_SDA | GPIOB_PIN_SCL); + vTaskDelay(delay); + + for (int i = 0; i < 10; i++) { + GPIO_ResetBits(GPIOB, GPIOB_PIN_SCL); + vTaskDelay(delay); + GPIO_SetBits(GPIOB, GPIOB_PIN_SCL); + vTaskDelay(delay); + } + + I2C_SoftwareResetCmd(I2Cx, DISABLE); + + i2c_device_init(); +} + +static void i2c_device_init(void) +{ + // Configure I2C SCL and SDA pins. + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.GPIO_Pin = GPIOB_PIN_SCL | GPIOB_PIN_SDA; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_Init(GPIOB, &GPIO_InitStructure); + + GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1); + GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_I2C1); + + // Reset I2C. + RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, ENABLE); + RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, DISABLE); + + // configure I2C1 + I2C_InitTypeDef I2C_InitStruct; + I2C_InitStruct.I2C_ClockSpeed = 100000; //Hz + I2C_InitStruct.I2C_Mode = I2C_Mode_I2C; + I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2; // 50% duty cycle + I2C_InitStruct.I2C_OwnAddress1 = 0x00; // not relevant in master mode + + // disable acknowledge when reading (can be changed later on) + I2C_InitStruct.I2C_Ack = I2C_Ack_Disable; + + I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; + I2C_Init(I2C1, &I2C_InitStruct); + + // enable I2C1 + I2C_Cmd(I2C1, ENABLE); +} + +void i2c_init() +{ + if (i2c_init_done == 1) { + return; + } + + i2c_semaphore = xSemaphoreCreateBinary(); + + if ( i2c_semaphore == NULL ) { + trigger_fault(FAULT_SOURCE_I2C); + } + else { + xSemaphoreGive(i2c_semaphore); + } + + RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); + + i2c_device_init(); + i2c_init_done = 1; +} + +static int i2c_check_busy_flag(void) +{ + const TickType_t i2c_timeout = 1000ul / portTICK_PERIOD_MS; + const TickType_t time_start = xTaskGetTickCount(); + + while (I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY)) { + const TickType_t time_now = xTaskGetTickCount(); + + if (time_now - time_start > i2c_timeout) { + i2c_error = 1; + return 0; + } + } + + return 1; +} + +static int i2c_check_event(uint32_t event) +{ + const TickType_t i2c_timeout = 1000ul / portTICK_PERIOD_MS; + const TickType_t time_start = xTaskGetTickCount(); + + while (!I2C_CheckEvent(I2Cx, event)) { + const TickType_t time_now = xTaskGetTickCount(); + + if (time_now - time_start > i2c_timeout) { + i2c_error = 1; + return 0; + } + } + + return 1; +} + +static int i2c_start(uint8_t device, uint8_t direction) +{ + I2C_GenerateSTART(I2Cx, ENABLE); + + // wait for bus free + if (!i2c_check_event(I2C_EVENT_MASTER_MODE_SELECT)) { + I2C_GenerateSTART(I2Cx, DISABLE); + return 0; + } + + I2C_Send7bitAddress(I2Cx, device << 1, direction); + + /* wait for I2C1 EV6, check if + * either Slave has acknowledged Master transmitter or + * Master receiver mode, depending on the transmission + * direction + */ + uint32_t event = 0; + if (direction == I2C_Direction_Transmitter) { + event = I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED; + } + else if (direction == I2C_Direction_Receiver) { + event = I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED; + } + else { + trigger_fault(FAULT_SOURCE_I2C); + } + + if (!i2c_check_event(event)) { + return 0; + } + + return 1; +} + +static int i2c_send(uint8_t data) +{ + I2C_SendData(I2Cx, data); + + // wait for I2C1 EV8_2 --> byte has been transmitted + return i2c_check_event(I2C_EVENT_MASTER_BYTE_TRANSMITTED); +} + +int i2c_write(uint8_t device, const uint8_t *txbuf, int len) +{ + if (i2c_init_done == 0) { + trigger_fault(FAULT_SOURCE_I2C); + } + + int success = i2c_check_busy_flag(); + + if (success) { + success = i2c_start(device, I2C_Direction_Transmitter); + } + + if (success) { + for (int i = 0; i < len; i++) { + success = i2c_send(txbuf[i]); + if (!success) { + break; + } + } + + I2C_GenerateSTOP(I2Cx, ENABLE); + success = i2c_check_event(I2C_EVENT_MASTER_BYTE_TRANSMITTED); + } + + return success; +} + +static int i2c_read_nobuscheck(uint8_t device, uint8_t *rxbuf, int len) +{ + if (i2c_init_done == 0) { + trigger_fault(FAULT_SOURCE_I2C); + } + + if (i2c_start(device, I2C_Direction_Receiver)) { + for (int i = 0; i < len; i++) { + if (i == len-1) { + I2C_AcknowledgeConfig(I2Cx, DISABLE); + } + else { + I2C_AcknowledgeConfig(I2Cx, ENABLE); + } + + // wait until one byte has been received, possibly timout + if (!i2c_check_event(I2C_EVENT_MASTER_BYTE_RECEIVED)) { + I2C_GenerateSTOP(I2Cx, ENABLE); + return 0; + } + + if (i == len-1) { + I2C_GenerateSTOP(I2Cx, ENABLE); + } + + rxbuf[i] = I2C_ReceiveData(I2Cx); + } + return len; + } + + return 0; +} + +int i2c_read(uint8_t device, uint8_t *rxbuf, int len) +{ + int success = i2c_check_busy_flag(); + + if (success) { + success = i2c_read_nobuscheck(device, rxbuf, len); + } + + return success; +} + +int i2c_read_from(uint8_t device, uint8_t address, uint8_t *rxbuf, int len) +{ + if (i2c_init_done == 0) { + trigger_fault(FAULT_SOURCE_I2C); + } + + int success = i2c_check_busy_flag(); + + if (success) { + success = i2c_start(device, I2C_Direction_Transmitter); + } + + if (success) { + success = i2c_send(address); + } + // Don't do a STOP + + if (success) { + success = i2c_read_nobuscheck(device, rxbuf, len); + } + + return success; +} + + + +void i2c_transaction_start() +{ + if (i2c_init_done == 0) { + trigger_fault(FAULT_SOURCE_I2C); + } + xSemaphoreTake(i2c_semaphore, portMAX_DELAY); +} + +void i2c_transaction_end() +{ + if (i2c_init_done == 0) { + trigger_fault(FAULT_SOURCE_I2C); + } + + if ( i2c_error ) { + i2c_recover_from_lockup(); + + i2c_error = 0; + } + + xSemaphoreGive(i2c_semaphore); +} + diff --git a/src/glutt-o-logique/leds.c b/src/glutt-o-logique/leds.c new file mode 100644 index 0000000..88b46bf --- /dev/null +++ b/src/glutt-o-logique/leds.c @@ -0,0 +1,42 @@ +#include "../../../common/src/GPIO/leds.c" + +#include "stm32f4xx_conf.h" + +#include "leds.h" + +void leds_turn_on(int l) { + + switch (l) { + case LED_GREEN: + GPIO_SetBits(GPIOD, GPIOD_BOARD_LED_GREEN); + break; + case LED_ORANGE: + GPIO_SetBits(GPIOD, GPIOD_BOARD_LED_ORANGE); + break; + case LED_RED: + GPIO_SetBits(GPIOD, GPIOD_BOARD_LED_RED); + break; + case LED_BLUE: + GPIO_SetBits(GPIOD, GPIOD_BOARD_LED_BLUE); + break; + + } +} + +void leds_turn_off(int l) { + + switch (l) { + case LED_GREEN: + GPIO_ResetBits(GPIOD, GPIOD_BOARD_LED_GREEN); + break; + case LED_ORANGE: + GPIO_ResetBits(GPIOD, GPIOD_BOARD_LED_ORANGE); + break; + case LED_RED: + GPIO_ResetBits(GPIOD, GPIOD_BOARD_LED_RED); + break; + case LED_BLUE: + GPIO_ResetBits(GPIOD, GPIOD_BOARD_LED_BLUE); + break; + } +} diff --git a/src/glutt-o-logique/leds.h b/src/glutt-o-logique/leds.h new file mode 100644 index 0000000..869a032 --- /dev/null +++ b/src/glutt-o-logique/leds.h @@ -0,0 +1,4 @@ +#define GPIOD_BOARD_LED_GREEN GPIO_Pin_12 +#define GPIOD_BOARD_LED_ORANGE GPIO_Pin_13 +#define GPIOD_BOARD_LED_RED GPIO_Pin_14 +#define GPIOD_BOARD_LED_BLUE GPIO_Pin_15 diff --git a/src/glutt-o-logique/main.c b/src/glutt-o-logique/main.c new file mode 100644 index 0000000..21df1d0 --- /dev/null +++ b/src/glutt-o-logique/main.c @@ -0,0 +1,69 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2016 Matthias P. Braendli, Maximilien Cuony + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. +*/ + +#include "stm32f4xx_conf.h" + +#include "leds.h" +#include "../../../common/src/Core/main.c" + + +void init() { + /* Initialise the onboard peripherals + * Four LEDs and one push-button + */ + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); + + // Configure PD12, PD13, PD14 and PD15 in output pushpull mode + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.GPIO_Pin = + GPIOD_BOARD_LED_GREEN | + GPIOD_BOARD_LED_ORANGE | + GPIOD_BOARD_LED_RED | + GPIOD_BOARD_LED_BLUE; + + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(GPIOD, &GPIO_InitStructure); + + // Init PushButton + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; // TODO is there an external pullup ? + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + + /* Setup Watchdog + * The IWDG runs at 32kHz. With a prescaler of 32 -> 1kHz. + * Counting to 2000 / 1000 = 2 seconds + */ + IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); + IWDG_SetPrescaler(IWDG_Prescaler_32); + IWDG_SetReload(2000); + IWDG_Enable(); +} diff --git a/src/glutt-o-logique/minmea.c b/src/glutt-o-logique/minmea.c new file mode 100644 index 0000000..10df198 --- /dev/null +++ b/src/glutt-o-logique/minmea.c @@ -0,0 +1 @@ +#include "../../../common/src/GPS/minmea.c" diff --git a/src/glutt-o-logique/pio.c b/src/glutt-o-logique/pio.c new file mode 100644 index 0000000..d8780fe --- /dev/null +++ b/src/glutt-o-logique/pio.c @@ -0,0 +1,187 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015 Matthias P. Braendli + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. +*/ + +#include "stm32f4xx_rcc.h" +#include "stm32f4xx_gpio.h" + +/* See pio.txt for PIO allocation details */ + +/* On GPIO C */ +#define GPIO_PIN_QRP_n GPIO_Pin_1 +#define GPIO_PIN_TX GPIO_Pin_2 +#define GPIO_PIN_1750_n GPIO_Pin_4 +#define GPIO_PIN_MOD_OFF GPIO_Pin_5 +#define GPIO_PIN_SQ_n GPIO_Pin_6 +#define GPIO_PIN_U GPIO_Pin_8 +#define GPIO_PIN_QRP_out GPIO_Pin_9 +#define GPIO_PIN_D GPIO_Pin_11 +#define GPIO_PIN_REPLIE_n GPIO_Pin_13 +#define GPIO_PIN_FAX_n GPIO_Pin_14 + + +#define GPIOC_OUTPUT_PINS ( \ + GPIO_PIN_TX | \ + GPIO_PIN_MOD_OFF | \ + GPIO_PIN_QRP_out | \ + 0) + +#undef GPIOC_OPENDRAIN_PINS +#undef GPIOC_INPUT_PU_PINS + +#define GPIOC_INPUT_PINS ( \ + GPIO_PIN_QRP_n | \ + GPIO_PIN_1750_n | \ + GPIO_PIN_SQ_n | \ + GPIO_PIN_U | \ + GPIO_PIN_D | \ + GPIO_PIN_REPLIE_n | \ + 0 ) + +#include "GPIO/pio.h" +#include "Core/common.h" +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "semphr.h" + +void read_fsm_input_task(void *pvParameters); + +struct fsm_input_signals_t pio_signals; + +void pio_init() +{ + GPIO_InitTypeDef GPIO_InitStructure; + + // Init pio + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); + + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_Pin = GPIOC_OUTPUT_PINS; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_Init(GPIOC, &GPIO_InitStructure); + +#if defined(GPIOC_OPENDRAIN_PINS) + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_Pin = GPIOC_OPENDRAIN_PINS; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; + GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; + GPIO_Init(GPIOC, &GPIO_InitStructure); +#endif + +#if defined(GPIOC_INPUT_PU_PINS) + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; + GPIO_InitStructure.GPIO_Pin = GPIOC_INPUT_PU_PINS; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_Init(GPIOC, &GPIO_InitStructure); +#endif + +#if defined(GPIOC_INPUT_PINS) + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; + GPIO_InitStructure.GPIO_Pin = GPIOC_INPUT_PINS; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_Init(GPIOC, &GPIO_InitStructure); +#endif + + xTaskCreate( + read_fsm_input_task, + "TaskPIO", + configMINIMAL_STACK_SIZE, + (void*) NULL, + tskIDLE_PRIORITY + 2UL, + NULL); +} + +void pio_set_fsm_signals(struct fsm_input_signals_t* sig) +{ + *sig = pio_signals; +} + +void read_fsm_input_task(void *pvParameters) +{ + while (1) { + pio_signals.qrp = + GPIO_ReadInputDataBit(GPIOC, GPIO_PIN_QRP_n) ? 0 : 1; + + pio_signals.tone_1750 = + GPIO_ReadInputDataBit(GPIOC, GPIO_PIN_1750_n) ? 0 : 1; + + pio_signals.sq = + GPIO_ReadInputDataBit(GPIOC, GPIO_PIN_SQ_n) ? 0 : 1; + + pio_signals.discrim_u = + GPIO_ReadInputDataBit(GPIOC, GPIO_PIN_U) ? 1 : 0; + + pio_signals.discrim_d = + GPIO_ReadInputDataBit(GPIOC, GPIO_PIN_D) ? 1 : 0; + + pio_signals.wind_generator_ok = + GPIO_ReadInputDataBit(GPIOC, GPIO_PIN_REPLIE_n) ? 1 : 0; + + pio_signals.sstv_mode = + GPIO_ReadInputDataBit(GPIOC, GPIO_PIN_FAX_n) ? 0 : 1; + + vTaskDelay(100 / portTICK_RATE_MS); + } +} + +void pio_set_tx(int on) +{ + if (on) { + GPIO_SetBits(GPIOC, GPIO_PIN_TX); + } + else { + GPIO_ResetBits(GPIOC, GPIO_PIN_TX); + } +} + +void pio_set_qrp(int on) +{ + if (on) { + GPIO_SetBits(GPIOC, GPIO_PIN_QRP_out); + } + else { + GPIO_ResetBits(GPIOC, GPIO_PIN_QRP_out); + } +} + +void pio_set_mod_off(int mod_off) +{ + if (mod_off) { + GPIO_SetBits(GPIOC, GPIO_PIN_MOD_OFF); + } + else { + GPIO_ResetBits(GPIOC, GPIO_PIN_MOD_OFF); + } +} + +int pio_read_button() { + return GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) == Bit_SET; +} diff --git a/src/glutt-o-logique/temperature.c b/src/glutt-o-logique/temperature.c new file mode 100644 index 0000000..780a019 --- /dev/null +++ b/src/glutt-o-logique/temperature.c @@ -0,0 +1,93 @@ +/* On wire connection: PA1 + */ + +#define TEMPERATURE_ONEWIRE_PIN GPIO_Pin_1 + +#include "stm32f4xx_conf.h" +#include "stm32f4xx.h" + +#include "tm_stm32f4_ds18b20.h" +#include "tm_stm32f4_onewire.h" +#include "Core/delay.h" + + +#include "../../../common/src/GPIO/temperature.c" + +const TickType_t _temperature_delay = 60000 / portTICK_PERIOD_MS; // 60s + +static TM_OneWire_t tm_onewire; + + + +void ds18b20_init() { + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); + + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.GPIO_Pin = TEMPERATURE_ONEWIRE_PIN; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + vTaskSuspendAll(); + TM_OneWire_Init(&tm_onewire, GPIOA, TEMPERATURE_ONEWIRE_PIN); + xTaskResumeAll(); +} + +int ds18b20_gettemp_one(float *temperature) { + + vTaskSuspendAll(); + + uint8_t rom_addr[8]; + + TM_DS18B20_StartAll(&tm_onewire); + int status = TM_OneWire_First(&tm_onewire); + if (status) { + //Save ROM number from device + TM_OneWire_GetFullROM(&tm_onewire, rom_addr); + TM_DS18B20_Start(&tm_onewire, rom_addr); + + // The sensor needs time to do the conversion + xTaskResumeAll(); + delay_ms(100); + vTaskSuspendAll(); + status = TM_DS18B20_Read(&tm_onewire, rom_addr, temperature); + } + + xTaskResumeAll(); + + return status; +} + +int ds18b20_gettemp(float *temperature) { + int status; + for (int i = 0; i < 10; i++) { + status = ds18b20_gettemp_one(temperature); + + if (status) { + break; + } + delay_ms(5); + } + return status; +} + +static void temperature_task(void *pvParameters) { + + while (1) { + + if (!_temperature_valid) { + ds18b20_init(); + } + + if (ds18b20_gettemp(&_temperature_last_value)) { + _temperature_valid = 1; + } else { + _temperature_valid = 0; + } + + vTaskDelay(_temperature_delay); + + } +} diff --git a/src/glutt-o-logique/usart.c b/src/glutt-o-logique/usart.c new file mode 100644 index 0000000..d174719 --- /dev/null +++ b/src/glutt-o-logique/usart.c @@ -0,0 +1,156 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2016 Matthias P. Braendli + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. +*/ + + +#include <stm32f4xx.h> +#include <stm32f4xx_usart.h> +#include <stm32f4xx_conf.h> + +/* USART 3 on PD8 and PD9 + * See pio.txt for PIO allocation details */ +const uint16_t GPIOD_PIN_USART3_TX = GPIO_Pin_8; +const uint16_t GPIOD_PIN_USART3_RX = GPIO_Pin_9; + +/* USART 2 on PA2 and PA3 */ +const uint16_t GPIOA_PIN_USART2_RX = GPIO_Pin_3; +const uint16_t GPIOA_PIN_USART2_TX = GPIO_Pin_2; + +static void usart_puts(USART_TypeDef*, const char*); + +#include "../../../common/includes/GPIO/usart.h" +#include "../../../common/src/GPIO/usart.c" + + +void usart_init() { + // ============== PC DEBUG USART =========== + RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); + + GPIO_InitTypeDef GPIO_InitStruct; + GPIO_InitStruct.GPIO_Pin = GPIOA_PIN_USART2_RX | GPIOA_PIN_USART2_TX; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; + GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; + GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_Init(GPIOA, &GPIO_InitStruct); + + GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2); + GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2); + + // Setup USART2 for 9600,8,N,1 + USART_InitTypeDef USART_InitStruct; + USART_InitStruct.USART_BaudRate = 9600; + USART_InitStruct.USART_WordLength = USART_WordLength_8b; + USART_InitStruct.USART_StopBits = USART_StopBits_1; + USART_InitStruct.USART_Parity = USART_Parity_No; + USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; + USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; + USART_Init(USART2, &USART_InitStruct); + +#if USART2_RECEIVE_ENABLE + // enable the USART2 receive interrupt + USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); + + NVIC_InitTypeDef NVIC_InitStructure; + NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 6; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); + + NVIC_SetPriority(USART2_IRQn, 6); +#endif + + // finally this enables the complete USART2 peripheral + USART_Cmd(USART2, ENABLE); +} + +void usart_gps_specific_init() { + + // ============== GPS USART =========== + // Setup GPIO D and connect to USART 3 + RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); + + GPIO_InitTypeDef GPIO_InitStruct; + GPIO_InitStruct.GPIO_Pin = GPIOD_PIN_USART3_RX | GPIOD_PIN_USART3_TX; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; + GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; + GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_Init(GPIOD, &GPIO_InitStruct); + + GPIO_PinAFConfig(GPIOD, GPIO_PinSource8, GPIO_AF_USART3); + GPIO_PinAFConfig(GPIOD, GPIO_PinSource9, GPIO_AF_USART3); + + // Setup USART3 for 9600,8,N,1 + USART_InitTypeDef USART_InitStruct; + USART_InitStruct.USART_BaudRate = 9600; + USART_InitStruct.USART_WordLength = USART_WordLength_8b; + USART_InitStruct.USART_StopBits = USART_StopBits_1; + USART_InitStruct.USART_Parity = USART_Parity_No; + USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; + USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; + USART_Init(USART3, &USART_InitStruct); + + + // enable the USART3 receive interrupt + USART_ITConfig(USART3, USART_IT_RXNE, ENABLE); + + NVIC_InitTypeDef NVIC_InitStructure; + NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 6; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); + + NVIC_SetPriority(USART3_IRQn, 6); + + // finally this enables the complete USART3 peripheral + USART_Cmd(USART3, ENABLE); +} + +// Make sure Tasks are suspended when this is called! +static void usart_puts(USART_TypeDef* USART, const char* str) { + while(*str) { + // wait until data register is empty + USART_SendData(USART, *str); + while(USART_GetFlagStatus(USART, USART_FLAG_TXE) == RESET) ; + str++; + } +} + +void USART3_IRQHandler(void) { + if (USART_GetITStatus(USART3, USART_IT_RXNE)) { + char t = USART3->DR; + usart_gps_process_char(t); + } +} + +void USART2_IRQHandler(void) { + if (USART_GetITStatus(USART2, USART_IT_RXNE)) { + char t = USART2->DR; + usart_process_char(t); + } +} |