From 5433c2ad509625bf72dabded77d12ca71279a383 Mon Sep 17 00:00:00 2001 From: eddyem Date: Thu, 16 Jul 2015 18:01:59 +0300 Subject: [PATCH] Added semi-HW 1-wire realisation (alpha-version) --- 1_wire/Makefile | 133 +++++++++ 1_wire/README | 7 + 1_wire/cdcacm.c | 314 ++++++++++++++++++++ 1_wire/cdcacm.h | 54 ++++ 1_wire/hardware_ini.c | 98 +++++++ 1_wire/hardware_ini.h | 76 +++++ 1_wire/ld/devices.data | 9 + 1_wire/ld/stm32f103x4.ld | 31 ++ 1_wire/ld/stm32f103x6.ld | 31 ++ 1_wire/ld/stm32f103x8.ld | 31 ++ 1_wire/ld/stm32f103xB.ld | 31 ++ 1_wire/ld/stm32f103xC.ld | 31 ++ 1_wire/ld/stm32f103xD.ld | 31 ++ 1_wire/ld/stm32f103xE.ld | 31 ++ 1_wire/ld/stm32f103xF.ld | 31 ++ 1_wire/ld/stm32f103xG.ld | 31 ++ 1_wire/main.c | 92 ++++++ 1_wire/main.h | 55 ++++ 1_wire/onewire.bin | Bin 0 -> 9816 bytes 1_wire/onewire.c | 526 ++++++++++++++++++++++++++++++++++ 1_wire/onewire.h | 136 +++++++++ 1_wire/sync.c | 93 ++++++ 1_wire/sync.h | 53 ++++ 1_wire/user_proto.c | 240 ++++++++++++++++ 1_wire/user_proto.h | 51 ++++ simple_cdc/hardware_ini.c | 23 +- simple_cdc/usb_cdc_simple.bin | Bin 6728 -> 6728 bytes 27 files changed, 2232 insertions(+), 7 deletions(-) create mode 100644 1_wire/Makefile create mode 100644 1_wire/README create mode 100644 1_wire/cdcacm.c create mode 100644 1_wire/cdcacm.h create mode 100644 1_wire/hardware_ini.c create mode 100644 1_wire/hardware_ini.h create mode 100644 1_wire/ld/devices.data create mode 100644 1_wire/ld/stm32f103x4.ld create mode 100644 1_wire/ld/stm32f103x6.ld create mode 100644 1_wire/ld/stm32f103x8.ld create mode 100644 1_wire/ld/stm32f103xB.ld create mode 100644 1_wire/ld/stm32f103xC.ld create mode 100644 1_wire/ld/stm32f103xD.ld create mode 100644 1_wire/ld/stm32f103xE.ld create mode 100644 1_wire/ld/stm32f103xF.ld create mode 100644 1_wire/ld/stm32f103xG.ld create mode 100644 1_wire/main.c create mode 100644 1_wire/main.h create mode 100755 1_wire/onewire.bin create mode 100644 1_wire/onewire.c create mode 100644 1_wire/onewire.h create mode 100644 1_wire/sync.c create mode 100644 1_wire/sync.h create mode 100644 1_wire/user_proto.c create mode 100644 1_wire/user_proto.h diff --git a/1_wire/Makefile b/1_wire/Makefile new file mode 100644 index 0000000..ffe6748 --- /dev/null +++ b/1_wire/Makefile @@ -0,0 +1,133 @@ +BINARY = onewire +BOOTPORT ?= /dev/ttyUSB0 +BOOTSPEED ?= 115200 +# change this linking script depending on particular MCU model, +# for example, if you have STM32F103VBT6, you should write: +LDSCRIPT = ld/stm32f103xB.ld +LIBNAME = opencm3_stm32f1 +DEFS = -DSTM32F1 -DEBUG + +OBJDIR = mk +INDEPENDENT_HEADERS= + +FP_FLAGS ?= -msoft-float +ARCH_FLAGS = -mthumb -mcpu=cortex-m3 $(FP_FLAGS) -mfix-cortex-m3-ldrd + +############################################################################### +# Executables +PREFIX ?= arm-none-eabi + +RM := rm -f +RMDIR := rmdir +CC := $(PREFIX)-gcc +LD := $(PREFIX)-gcc +AR := $(PREFIX)-ar +AS := $(PREFIX)-as +OBJCOPY := $(PREFIX)-objcopy +OBJDUMP := $(PREFIX)-objdump +GDB := $(PREFIX)-gdb +STFLASH = $(shell which st-flash) +STBOOT = $(shell which stm32flash) + +############################################################################### +# Source files +LDSCRIPT ?= $(BINARY).ld +SRC = $(wildcard *.c) +OBJS = $(addprefix $(OBJDIR)/, $(SRC:%.c=%.o)) + +ifeq ($(strip $(OPENCM3_DIR)),) +OPENCM3_DIR := /usr/local/arm-none-eabi +$(info Using $(OPENCM3_DIR) path to library) +endif + +INCLUDE_DIR = $(OPENCM3_DIR)/include +LIB_DIR = $(OPENCM3_DIR)/lib +SCRIPT_DIR = $(OPENCM3_DIR)/scripts + +############################################################################### +# C flags +CFLAGS += -Os -g +CFLAGS += -Wall -Wextra -Wshadow -Wimplicit-function-declaration +CFLAGS += -Wredundant-decls +# -Wmissing-prototypes -Wstrict-prototypes +CFLAGS += -fno-common -ffunction-sections -fdata-sections + +############################################################################### +# C & C++ preprocessor common flags +CPPFLAGS += -MD +CPPFLAGS += -Wall -Werror +CPPFLAGS += -I$(INCLUDE_DIR) $(DEFS) + +############################################################################### +# Linker flags +LDFLAGS += --static -nostartfiles +LDFLAGS += -L$(LIB_DIR) +LDFLAGS += -T$(LDSCRIPT) +LDFLAGS += -Wl,-Map=$(*).map +LDFLAGS += -Wl,--gc-sections + +############################################################################### +# Used libraries +LDLIBS += -l$(LIBNAME) +LDLIBS += -Wl,--start-group -lc -lgcc -Wl,--end-group + +.SUFFIXES: .elf .bin .hex .srec .list .map .images +.SECONDEXPANSION: +.SECONDARY: + +ELF := $(OBJDIR)/$(BINARY).elf +LIST := $(OBJDIR)/$(BINARY).list +BIN := $(BINARY).bin +HEX := $(BINARY).hex + +all: bin + +elf: $(ELF) +bin: $(BIN) +hex: $(HEX) +list: $(LIST) + +$(OBJDIR): + mkdir $(OBJDIR) + +$(OBJDIR)/%.o: %.c + @printf " CC $<\n" + $(CC) $(CFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) -o $@ -c $< + +$(SRC) : %.c : %.h $(INDEPENDENT_HEADERS) + @touch $@ + +%.h: ; + +$(BIN): $(ELF) + @printf " OBJCOPY $(BIN)\n" + $(OBJCOPY) -Obinary $(ELF) $(BIN) + +$(HEX): $(ELF) + @printf " OBJCOPY $(HEX)\n" + $(OBJCOPY) -Oihex $(ELF) $(HEX) + +$(LIST): $(ELF) + @printf " OBJDUMP $(LIST)\n" + $(OBJDUMP) -S $(ELF) > $(LIST) + +$(ELF): $(OBJDIR) $(OBJS) $(LDSCRIPT) $(LIB_DIR)/lib$(LIBNAME).a + @printf " LD $(ELF)\n" + $(LD) $(LDFLAGS) $(ARCH_FLAGS) $(OBJS) $(LDLIBS) -o $(ELF) + +clean: + @printf " CLEAN\n" + $(RM) $(OBJS) $(OBJDIR)/*.d $(ELF) $(HEX) $(LIST) $(OBJDIR)/*.map + $(RMDIR) $(OBJDIR) + +flash: $(BIN) + @printf " FLASH $(BIN)\n" + $(STFLASH) write $(BIN) 0x8000000 + +boot: $(BIN) + @printf " LOAD $(BIN) through bootloader\n" + $(STBOOT) -b$(BOOTSPEED) $(BOOTPORT) -w $(BIN) + +.PHONY: clean elf hex list flash boot + +#-include $(OBJS:.o=.d) diff --git a/1_wire/README b/1_wire/README new file mode 100644 index 0000000..8abf06f --- /dev/null +++ b/1_wire/README @@ -0,0 +1,7 @@ +My approach to semi-hardware 1-wire realisation based on DMA+TIM2 + +written for chinese devboard based on STM32F103RBT6 + +Press H for help + +// Still some troubles left: for example, can't read ROM; also the code isn't fully done yet diff --git a/1_wire/cdcacm.c b/1_wire/cdcacm.c new file mode 100644 index 0000000..5f032ad --- /dev/null +++ b/1_wire/cdcacm.c @@ -0,0 +1,314 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Gareth McMullin + * Copyright 2014 Edward V. Emelianov + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include "cdcacm.h" +#include "user_proto.h" +#include "main.h" + +// Buffer for USB Tx +static uint8_t USB_Tx_Buffer[USB_TX_DATA_SIZE]; +static uint8_t USB_Tx_ptr = 0; +// connection flag +uint8_t USB_connected = 0; +static const struct usb_device_descriptor dev = { + .bLength = USB_DT_DEVICE_SIZE, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = USB_CLASS_CDC, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = 64, + .idVendor = 0x0483, + .idProduct = 0x5740, + .bcdDevice = 0x0200, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 3, + .bNumConfigurations = 1, +}; + +char usbdatabuf[USB_RX_DATA_SIZE]; // buffer for received data +int usbdatalen = 0; // lenght of received data + +/* + * This notification endpoint isn't implemented. According to CDC spec its + * optional, but its absence causes a NULL pointer dereference in Linux + * cdc_acm driver. + */ +static const struct usb_endpoint_descriptor comm_endp[] = {{ + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x83, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 16, + .bInterval = 255, +}}; + +static const struct usb_endpoint_descriptor data_endp[] = {{ + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x01, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = 64, + .bInterval = 1, +}, { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x82, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = 64, + .bInterval = 1, +}}; + +static const struct { + struct usb_cdc_header_descriptor header; + struct usb_cdc_call_management_descriptor call_mgmt; + struct usb_cdc_acm_descriptor acm; + struct usb_cdc_union_descriptor cdc_union; +} __attribute__((packed)) cdcacm_functional_descriptors = { + .header = { + .bFunctionLength = sizeof(struct usb_cdc_header_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_HEADER, + .bcdCDC = 0x0110, + }, + .call_mgmt = { + .bFunctionLength = + sizeof(struct usb_cdc_call_management_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT, + .bmCapabilities = 0, + .bDataInterface = 1, + }, + .acm = { + .bFunctionLength = sizeof(struct usb_cdc_acm_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_ACM, + .bmCapabilities = 0, + }, + .cdc_union = { + .bFunctionLength = sizeof(struct usb_cdc_union_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_UNION, + .bControlInterface = 0, + .bSubordinateInterface0 = 1, + }, +}; + +static const struct usb_interface_descriptor comm_iface[] = {{ + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_CDC, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, + .bInterfaceProtocol = USB_CDC_PROTOCOL_AT, + .iInterface = 0, + + .endpoint = comm_endp, + + .extra = &cdcacm_functional_descriptors, + .extralen = sizeof(cdcacm_functional_descriptors), +}}; + +static const struct usb_interface_descriptor data_iface[] = {{ + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 1, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_DATA, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = 0, + + .endpoint = data_endp, +}}; + +static const struct usb_interface ifaces[] = {{ + .num_altsetting = 1, + .altsetting = comm_iface, +}, { + .num_altsetting = 1, + .altsetting = data_iface, +}}; + +static const struct usb_config_descriptor config = { + .bLength = USB_DT_CONFIGURATION_SIZE, + .bDescriptorType = USB_DT_CONFIGURATION, + .wTotalLength = 0, + .bNumInterfaces = 2, + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = 0x80, + .bMaxPower = 0x32, + + .interface = ifaces, +}; + +static const char *usb_strings[] = { + "Organisation, author", + "device", + "version", +}; + +// default line coding: B115200, 1stop, 8bits, parity none +struct usb_cdc_line_coding linecoding = { + .dwDTERate = 115200, + .bCharFormat = USB_CDC_1_STOP_BITS, + .bParityType = USB_CDC_NO_PARITY, + .bDataBits = 8, +}; + +/* Buffer to be used for control requests. */ +uint8_t usbd_control_buffer[128]; + +/** + * This function runs every time it gets a request for control parameters get/set + * parameter SET_LINE_CODING used to change USART1 parameters: if you want to + * change them, just connect through USB with required parameters + */ +static int cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, + uint16_t *len, void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req)){ + (void)complete; + (void)buf; + (void)usbd_dev; + char local_buf[10]; + struct usb_cdc_line_coding lc; + + switch (req->bRequest) { + case SET_CONTROL_LINE_STATE:{ + if(req->wValue){ // terminal is opened + USB_connected = 1; + }else{ // terminal is closed + USB_connected = 0; + } + /* + * This Linux cdc_acm driver requires this to be implemented + * even though it's optional in the CDC spec, and we don't + * advertise it in the ACM functional descriptor. + */ + struct usb_cdc_notification *notif = (void *)local_buf; + /* We echo signals back to host as notification. */ + notif->bmRequestType = 0xA1; + notif->bNotification = USB_CDC_NOTIFY_SERIAL_STATE; + notif->wValue = 0; + notif->wIndex = 0; + notif->wLength = 2; + local_buf[8] = req->wValue & 3; + local_buf[9] = 0; + usbd_ep_write_packet(usbd_dev, 0x83, local_buf, 10); + }break; + case SET_LINE_CODING: + if (!len || (*len != sizeof(struct usb_cdc_line_coding))) + return 0; + memcpy((void *)&lc, (void *)*buf, *len); + // Mark & Space parity don't support by hardware, check it + if(lc.bParityType == USB_CDC_MARK_PARITY || lc.bParityType == USB_CDC_SPACE_PARITY){ + return 0; // error + }else{ +// memcpy((void *)&linecoding, (void *)&lc, sizeof(struct usb_cdc_line_coding)); +// UART_setspeed(USART1, &linecoding); + } + break; + case GET_LINE_CODING: // return linecoding buffer + if(len && *len == sizeof(struct usb_cdc_line_coding)) + memcpy((void *)*buf, (void *)&linecoding, sizeof(struct usb_cdc_line_coding)); + //usbd_ep_write_packet(usbd_dev, 0x83, (char*)&linecoding, sizeof(linecoding)); + break; + default: + return 0; + } + return 1; +} + +static void cdcacm_data_rx_cb(usbd_device *usbd_dev, uint8_t ep){ + (void)ep; + int len = usbd_ep_read_packet(usbd_dev, 0x01, usbdatabuf + usbdatalen, USB_RX_DATA_SIZE - usbdatalen); + usbdatalen += len; + if(usbdatalen >= USB_RX_DATA_SIZE){ // buffer overflow - drop all its contents + usbdatalen = 0; + } +} + +static void cdcacm_data_tx_cb(usbd_device *usbd_dev, uint8_t ep){ + (void)ep; + (void)usbd_dev; + + usb_send_buffer(); +} + +static void cdcacm_set_config(usbd_device *usbd_dev, uint16_t wValue) +{ + (void)wValue; + (void)usbd_dev; + + usbd_ep_setup(usbd_dev, 0x01, USB_ENDPOINT_ATTR_BULK, USB_RX_DATA_SIZE, cdcacm_data_rx_cb); + usbd_ep_setup(usbd_dev, 0x82, USB_ENDPOINT_ATTR_BULK, USB_TX_DATA_SIZE, cdcacm_data_tx_cb); + usbd_ep_setup(usbd_dev, 0x83, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL); + + usbd_register_control_callback( + usbd_dev, + USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, + USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, + cdcacm_control_request); +} + +static usbd_device *current_usb = NULL; + +usbd_device *USB_init(){ + current_usb = usbd_init(&stm32f103_usb_driver, &dev, &config, + usb_strings, 3, usbd_control_buffer, sizeof(usbd_control_buffer)); + if(!current_usb) return NULL; + usbd_register_set_config_callback(current_usb, cdcacm_set_config); + return current_usb; +} + +mutex_t send_block_mutex = MUTEX_UNLOCKED; +/** + * Put byte into USB buffer to send + * @param byte - a byte to put into a buffer + */ +void usb_send(uint8_t byte){ + mutex_lock(&send_block_mutex); + USB_Tx_Buffer[USB_Tx_ptr++] = byte; + mutex_unlock(&send_block_mutex); + if(USB_Tx_ptr == USB_TX_DATA_SIZE){ // buffer can be overflowed - send it! + usb_send_buffer(); + } +} + +/** + * Send all data in buffer over USB + * this function runs when buffer is full or on SysTick + */ +void usb_send_buffer(){ + if(MUTEX_LOCKED == mutex_trylock(&send_block_mutex)) return; + if(USB_Tx_ptr){ + if(current_usb && USB_connected){ + // usbd_ep_write_packet return 0 if previous packet isn't transmit yet + while(USB_Tx_ptr != usbd_ep_write_packet(current_usb, 0x82, USB_Tx_Buffer, USB_Tx_ptr)); + usbd_poll(current_usb); + } + USB_Tx_ptr = 0; + } + mutex_unlock(&send_block_mutex); +} diff --git a/1_wire/cdcacm.h b/1_wire/cdcacm.h new file mode 100644 index 0000000..1051d83 --- /dev/null +++ b/1_wire/cdcacm.h @@ -0,0 +1,54 @@ +/* + * ccdcacm.h + * + * Copyright 2014 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#pragma once +#ifndef __CCDCACM_H__ +#define __CCDCACM_H__ + +#include + +// commands through EP0 +#define SEND_ENCAPSULATED_COMMAND 0x00 +#define GET_ENCAPSULATED_RESPONSE 0x01 +#define SET_COMM_FEATURE 0x02 +#define GET_COMM_FEATURE 0x03 +#define CLEAR_COMM_FEATURE 0x04 +#define SET_LINE_CODING 0x20 +#define GET_LINE_CODING 0x21 +#define SET_CONTROL_LINE_STATE 0x22 +#define SEND_BREAK 0x23 + +// Size of input/output buffers +#define USB_TX_DATA_SIZE 64 +#define USB_RX_DATA_SIZE 64 + +// USB connection flag +extern uint8_t USB_connected; +extern struct usb_cdc_line_coding linecoding; + +extern char usbdatabuf[]; +extern int usbdatalen; + +usbd_device *USB_init(); +void usb_send(uint8_t byte); +void usb_send_buffer(); + +#endif // __CCDCACM_H__ diff --git a/1_wire/hardware_ini.c b/1_wire/hardware_ini.c new file mode 100644 index 0000000..8c80639 --- /dev/null +++ b/1_wire/hardware_ini.c @@ -0,0 +1,98 @@ +/* + * hardware_ini.c - functions for HW initialisation + * + * Copyright 2014 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +/* + * All hardware-dependent initialisation & definition should be placed here + * and in hardware_ini.h + * + */ + +#include "main.h" +#include "hardware_ini.h" + +/** + * GPIO initialisaion: clocking + pins setup + */ +void GPIO_init(){ + rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPAEN | + RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN | + RCC_APB2ENR_IOPEEN); + // Buttons: pull-up input + gpio_set_mode(BTNS_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, + BTN_S2_PIN | BTN_S3_PIN); + // turn on pull-up + gpio_set(BTNS_PORT, BTN_S2_PIN | BTN_S3_PIN); + // LEDS: opendrain output + gpio_set_mode(LEDS_PORT, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, + LED_D1_PIN | LED_D2_PIN); + // turn off LEDs + gpio_set(LEDS_PORT, LED_D1_PIN | LED_D2_PIN); + // test pin PC10: Push-Pull +#ifdef EBUG + gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO10); +#endif +/* + // USB_DISC: push-pull + gpio_set_mode(USB_DISC_PORT, GPIO_MODE_OUTPUT_2_MHZ, + GPIO_CNF_OUTPUT_PUSHPULL, USB_DISC_PIN); + // USB_POWER: open drain, externall pull down with R7 (22k) + gpio_set_mode(USB_POWER_PORT, GPIO_MODE_INPUT, + GPIO_CNF_INPUT_FLOAT, USB_POWER_PIN); +*/ +} + +/* + * SysTick used for system timer with period of 1ms + */ +void SysTick_init(){ + systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8); // Systyck: 72/8=9MHz + systick_set_reload(8999); // 9000 pulses: 1kHz + systick_interrupt_enable(); + systick_counter_enable(); +} + +// check buttons S2/S3 +void check_btns(){ + static uint8_t oldstate[2] = {1,1}; // old buttons state + uint8_t newstate[2], i; + static uint32_t Old_timer[2] = {0,0}; + newstate[0] = gpio_get(BTNS_PORT, BTN_S2_PIN) ? 1 : 0; + newstate[1] = gpio_get(BTNS_PORT, BTN_S3_PIN) ? 1 : 0; + for(i = 0; i < 2; i++){ + uint8_t new = newstate[i]; + // pause for 60ms + uint32_t O = Old_timer[i]; + if(O){ + if(Timer - O > 60 || O > Timer){ + P("Button S"); + usb_send('2' + i); + if(new) P("released"); + else P("pressed"); + newline(); + oldstate[i] = new; + Old_timer[i] = 0; + } + } + else if(new != oldstate[i]){ + Old_timer[i] = Timer; + } + } +} diff --git a/1_wire/hardware_ini.h b/1_wire/hardware_ini.h new file mode 100644 index 0000000..ff0311f --- /dev/null +++ b/1_wire/hardware_ini.h @@ -0,0 +1,76 @@ +/* + * hardware_ini.h + * + * Copyright 2014 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#pragma once +#ifndef __HARDWARE_INI_H__ +#define __HARDWARE_INI_H__ + +/* + * Timers: + * SysTick - system time + */ + + +void GPIO_init(); +void SysTick_init(); + +/* + * Buttons on devboard + */ +#define BTNS_PORT GPIOC +// PCO -- S2 +#define BTN_S2_PIN GPIO0 +// PC1 -- S3 +#define BTN_S3_PIN GPIO1 + +/* + * LEDS: PB9 for D1, PB8 for D2 + */ +#define LEDS_PORT GPIOB +#define LED_D1_PIN GPIO9 +#define LED_D2_PIN GPIO8 + +/* + * USB interface + * connect boot1 jumper to gnd, boot0 to gnd; and reconnect boot0 to +3.3 to boot flash + */ +/* +// USB_DICS (disconnect) - PC11 +#define USB_DISC_PIN GPIO11 +#define USB_DISC_PORT GPIOC +// USB_POWER (high level when USB connected to PC) +#define USB_POWER_PIN GPIO10 +#define USB_POWER_PORT GPIOC +// change signal level on USB diconnect pin +#define usb_disc_high() gpio_set(USB_DISC_PORT, USB_DISC_PIN) +#define usb_disc_low() gpio_clear(USB_DISC_PORT, USB_DISC_PIN) +// in case of n-channel FET on 1.5k pull-up change on/off disconnect means low level +// in case of pnp bipolar transistor or p-channel FET on 1.5k pull-up disconnect means high level +#define usb_disconnect() usb_disc_high() +#define usb_connect() usb_disc_low() +*/ +// my simple devboard have no variants for programmed connection/disconnection of USB +#define usb_disconnect() +#define usb_connect() + +void check_btns(); + +#endif // __HARDWARE_INI_H__ diff --git a/1_wire/ld/devices.data b/1_wire/ld/devices.data new file mode 100644 index 0000000..7f29538 --- /dev/null +++ b/1_wire/ld/devices.data @@ -0,0 +1,9 @@ +stm32f103?4* stm32f1 ROM=16K RAM=6K +stm32f103?6* stm32f1 ROM=32K RAM=10K +stm32f103?8* stm32f1 ROM=64K RAM=20K +stm32f103?b* stm32f1 ROM=128K RAM=20K +stm32f103?c* stm32f1 ROM=256K RAM=48K +stm32f103?d* stm32f1 ROM=384K RAM=64K +stm32f103?e* stm32f1 ROM=512K RAM=64K +stm32f103?f* stm32f1 ROM=768K RAM=96K +stm32f103?g* stm32f1 ROM=1024K RAM=96K diff --git a/1_wire/ld/stm32f103x4.ld b/1_wire/ld/stm32f103x4.ld new file mode 100644 index 0000000..efed65e --- /dev/null +++ b/1_wire/ld/stm32f103x4.ld @@ -0,0 +1,31 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Karl Palsson + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Linker script for STM32F100x4, 16K flash, 4K RAM. */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 16K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 6K +} + +/* Include the common ld script. */ +INCLUDE libopencm3_stm32f1.ld + diff --git a/1_wire/ld/stm32f103x6.ld b/1_wire/ld/stm32f103x6.ld new file mode 100644 index 0000000..13f05f9 --- /dev/null +++ b/1_wire/ld/stm32f103x6.ld @@ -0,0 +1,31 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Karl Palsson + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Linker script for STM32F100x4, 16K flash, 4K RAM. */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 32K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 10K +} + +/* Include the common ld script. */ +INCLUDE libopencm3_stm32f1.ld + diff --git a/1_wire/ld/stm32f103x8.ld b/1_wire/ld/stm32f103x8.ld new file mode 100644 index 0000000..2c4640f --- /dev/null +++ b/1_wire/ld/stm32f103x8.ld @@ -0,0 +1,31 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Karl Palsson + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Linker script for STM32F100x4, 16K flash, 4K RAM. */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 64K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K +} + +/* Include the common ld script. */ +INCLUDE libopencm3_stm32f1.ld + diff --git a/1_wire/ld/stm32f103xB.ld b/1_wire/ld/stm32f103xB.ld new file mode 100644 index 0000000..138444d --- /dev/null +++ b/1_wire/ld/stm32f103xB.ld @@ -0,0 +1,31 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Karl Palsson + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Linker script for STM32F100x4, 16K flash, 4K RAM. */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K +} + +/* Include the common ld script. */ +INCLUDE libopencm3_stm32f1.ld + diff --git a/1_wire/ld/stm32f103xC.ld b/1_wire/ld/stm32f103xC.ld new file mode 100644 index 0000000..fda76bf --- /dev/null +++ b/1_wire/ld/stm32f103xC.ld @@ -0,0 +1,31 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Karl Palsson + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Linker script for STM32F100x4, 16K flash, 4K RAM. */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 256K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 48K +} + +/* Include the common ld script. */ +INCLUDE libopencm3_stm32f1.ld + diff --git a/1_wire/ld/stm32f103xD.ld b/1_wire/ld/stm32f103xD.ld new file mode 100644 index 0000000..0f996c2 --- /dev/null +++ b/1_wire/ld/stm32f103xD.ld @@ -0,0 +1,31 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Karl Palsson + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Linker script for STM32F100x4, 16K flash, 4K RAM. */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 384K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 64K +} + +/* Include the common ld script. */ +INCLUDE libopencm3_stm32f1.ld + diff --git a/1_wire/ld/stm32f103xE.ld b/1_wire/ld/stm32f103xE.ld new file mode 100644 index 0000000..b0fcb69 --- /dev/null +++ b/1_wire/ld/stm32f103xE.ld @@ -0,0 +1,31 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Karl Palsson + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Linker script for STM32F100x4, 16K flash, 4K RAM. */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 512K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 64K +} + +/* Include the common ld script. */ +INCLUDE libopencm3_stm32f1.ld + diff --git a/1_wire/ld/stm32f103xF.ld b/1_wire/ld/stm32f103xF.ld new file mode 100644 index 0000000..62d47db --- /dev/null +++ b/1_wire/ld/stm32f103xF.ld @@ -0,0 +1,31 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Karl Palsson + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Linker script for STM32F100x4, 16K flash, 4K RAM. */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 768K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 96K +} + +/* Include the common ld script. */ +INCLUDE libopencm3_stm32f1.ld + diff --git a/1_wire/ld/stm32f103xG.ld b/1_wire/ld/stm32f103xG.ld new file mode 100644 index 0000000..0c0c968 --- /dev/null +++ b/1_wire/ld/stm32f103xG.ld @@ -0,0 +1,31 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Karl Palsson + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Linker script for STM32F100x4, 16K flash, 4K RAM. */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 1024K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 96K +} + +/* Include the common ld script. */ +INCLUDE libopencm3_stm32f1.ld + diff --git a/1_wire/main.c b/1_wire/main.c new file mode 100644 index 0000000..bb00ffe --- /dev/null +++ b/1_wire/main.c @@ -0,0 +1,92 @@ +/* + * main.c + * + * Copyright 2014 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "main.h" +#include "hardware_ini.h" +#include "cdcacm.h" +#include "onewire.h" + +volatile uint32_t Timer = 0; // global timer (milliseconds) +usbd_device *usbd_dev; + +int main(){ + uint32_t Old_timer = 0; + + // RCC clocking: 8MHz oscillator -> 72MHz system + rcc_clock_setup_in_hse_8mhz_out_72mhz(); + + GPIO_init(); + + usb_disconnect(); // turn off USB while initializing all + + // USB + usbd_dev = USB_init(); + + // SysTick is a system timer with 1ms period + SysTick_init(); + + // wait a little and then turn on USB pullup +// for (i = 0; i < 0x800000; i++) +// __asm__("nop"); + + usb_connect(); // turn on USB + + init_ow_dmatimer(); + + while(1){ + usbd_poll(usbd_dev); + if(usbdatalen){ // there's something in USB buffer + usbdatalen = parce_incoming_buf(usbdatabuf, usbdatalen); + } + //check_and_parce_UART(USART1); // also check data in UART buffers + check_btns(); + if(Timer - Old_timer > 999){ // one-second cycle + Old_timer += 1000; + }else if(Timer < Old_timer){ // Timer overflow + Old_timer = 0; + } + OW_process(); + } +} + + +/** + * SysTick interrupt: increment global time & send data buffer through USB + */ +void sys_tick_handler(){ + Timer++; + usbd_poll(usbd_dev); + usb_send_buffer(); +} + +// pause function, delay in ms +void Delay(uint16_t _U_ time){ + uint32_t waitto = Timer + time; + while(Timer < waitto); +} + +/** + * print current time in milliseconds: 4 bytes for ovrvlow + 4 bytes for time + * with ' ' as delimeter + */ +void print_time(){ + print_int(Timer); +} diff --git a/1_wire/main.h b/1_wire/main.h new file mode 100644 index 0000000..0cc7714 --- /dev/null +++ b/1_wire/main.h @@ -0,0 +1,55 @@ +/* + * main.h + * + * Copyright 2014 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + + +#pragma once +#ifndef __MAIN_H__ +#define __MAIN_H__ + +#include +#include // memcpy +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ADC_CHANNELS_NUMBER (10) + +#include "sync.h" // mutexes +#include "user_proto.h" + +#define _U_ __attribute__((__unused__)) +#define U8(x) ((uint8_t) x) +#define U16(x) ((uint16_t) x) +#define U32(x) ((uint32_t) x) + +extern volatile uint32_t Timer; // global timer (milliseconds) +void Delay(uint16_t time); + +#endif // __MAIN_H__ + diff --git a/1_wire/onewire.bin b/1_wire/onewire.bin new file mode 100755 index 0000000000000000000000000000000000000000..2ce1fcacb98beaff7e86aac771b6698d04e21187 GIT binary patch literal 9816 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 literal 0 HcmV?d00001 diff --git a/1_wire/onewire.c b/1_wire/onewire.c new file mode 100644 index 0000000..12aff82 --- /dev/null +++ b/1_wire/onewire.c @@ -0,0 +1,526 @@ +/* + * onewire.c - functions to work with 1-wire devices + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +#include "onewire.h" +#include "user_proto.h" + +OW_ID id_array[OW_MAX_NUM]; // 1-wire devices ID buffer (not more than eight) +uint8_t dev_amount = 0; // amount of 1-wire devices + + +// states of 1-wire processing queue +typedef enum{ + OW_OFF_STATE, // not working + OW_RESET_STATE, // reset bus + OW_SEND_STATE, // send data + OW_READ_STATE, // wait for reading +} OW_States; +volatile OW_States OW_State = OW_OFF_STATE; // 1-wire state, 0-not runned + +void (*ow_process_resdata)() = NULL; + + +uint16_t tim2_buff[TIM2_DMABUFF_SIZE]; +uint16_t tim2_inbuff[TIM2_DMABUFF_SIZE]; +int tum2buff_ctr = 0; +uint8_t ow_done = 1; + +/** + * this function sends bits of ow_byte (LSB first) to 1-wire line + * @param ow_byte - byte to convert + * @param Nbits - number of bits to send + * @param ini - 1 to zero counter + */ +uint8_t OW_add_byte(uint8_t ow_byte){ + uint8_t i, byte; + for(i = 0; i < 8; i++){ + if(ow_byte & 0x01){ + byte = BIT_ONE_P; + }else{ + byte = BIT_ZERO_P; + } + if(tum2buff_ctr == TIM2_DMABUFF_SIZE){ + ERR("Tim2 buffer overflow"); + return 0; // avoid buffer overflow + } + tim2_buff[tum2buff_ctr++] = byte; + ow_byte >>= 1; + } + INT(tum2buff_ctr); + DBG(" bytes in send buffer\n"); + return 1; +} + + + +/** + * Adds Nbytes bytes 0xff for reading sequence + */ +uint8_t OW_add_read_seq(uint8_t Nbytes){ + uint8_t i; + if(Nbytes == 0) return 0; + Nbytes *= 8; // 8 bits for each byte + for(i = 0; i < Nbytes; i++){ + if(tum2buff_ctr == TIM2_DMABUFF_SIZE){ + ERR("Tim2 buffer overflow"); + return 0; + } + tim2_buff[tum2buff_ctr++] = BIT_READ_P; + } + INT(tum2buff_ctr); + DBG(" bytes in send buffer\n"); + return 1; +} + +/** + * Fill output buffer with data from 1-wire + * @param start_idx - index from which to start (byte number) + * @param N - data length (in **bytes**) + * @outbuf - where to place data + */ +void read_from_OWbuf(uint8_t start_idx, uint8_t N, uint8_t *outbuf){ + start_idx *= 8; + uint8_t i, j, last = start_idx + N * 8, byte; + if(last >= TIM2_DMABUFF_SIZE) last = TIM2_DMABUFF_SIZE; + for(i = start_idx; i < last;){ + byte = 0; + for(j = 0; j < 8; j++){ + byte >>= 1; + INT(tim2_inbuff[i]); + DBG(" "); + if(tim2_inbuff[i++] < ONE_ZERO_BARRIER) + byte |= 0x80; + } + *outbuf++ = byte; + DBG("readed \n"); + } +} +// there's a mistake in opencm3, so redefine this if needed (TIM_CCMR2_CC3S_IN_TI1 -> TIM_CCMR2_CC3S_IN_TI4) +#ifndef TIM_CCMR2_CC3S_IN_TI4 +#define TIM_CCMR2_CC3S_IN_TI4 (2) +#endif +void init_ow_dmatimer(){ // tim2_ch4 - PA3, no remap + gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, + GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, GPIO3); + rcc_periph_clock_enable(RCC_TIM2); + rcc_periph_clock_enable(RCC_DMA1); + timer_reset(TIM2); + // timers have frequency of 1MHz -- 1us for one step + // 36MHz of APB1 + timer_set_mode(TIM2, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); + // 72MHz div 72 = 1MHz + // TODO: WHY 71 if freq = 36MHz? + TIM2_PSC = 71; // prescaler is (div - 1) + TIM2_CR1 = TIM_CR1_ARPE; // bufferize ARR/CCR + TIM2_ARR = RESET_LEN; + // PWM_OUT: TIM2_CH4; capture: TIM2_CH3 + // PWM edge-aligned mode & enable preload for CCR4, CC3 takes input from TI4 + TIM2_CCMR2 = TIM_CCMR2_OC4M_PWM1 | TIM_CCMR2_OC4PE | TIM_CCMR2_CC3S_IN_TI4; + TIM2_CCR4 = 0; // set output value to 1 by clearing CCR4 + TIM2_EGR = TIM_EGR_UG; // update values of ARR & CCR4 + // set low polarity for CC4, high for CC3 & enable CC4 out and CC3 in + TIM2_CCER = TIM_CCER_CC4P | TIM_CCER_CC4E | TIM_CCER_CC3E; + + // TIM2_CH4 - DMA1, channel 7 + dma_channel_reset(DMA1, DMA_CHANNEL7); + DMA1_CCR7 = DMA_CCR_DIR | DMA_CCR_MINC | DMA_CCR_PSIZE_16BIT | DMA_CCR_MSIZE_16BIT + | DMA_CCR_TEIE | DMA_CCR_TCIE | DMA_CCR_PL_HIGH; + nvic_enable_irq(NVIC_DMA1_CHANNEL7_IRQ); // enable dma1_channel7_isr + tum2buff_ctr = 0; + DBG("OW INITED\n"); +#ifdef EBUG + gpio_set(GPIOC, GPIO10); +#endif +} + +void run_dmatimer(){ + ow_done = 0; + TIM2_CR1 = 0; + adc_disable_dma(ADC1); // turn off DMA & ADC + adc_off(ADC1); + DMA1_IFCR = DMA_ISR_TEIF7|DMA_ISR_HTIF7|DMA_ISR_TCIF7|DMA_ISR_GIF7 | + DMA_ISR_TEIF1|DMA_ISR_HTIF1|DMA_ISR_TCIF1|DMA_ISR_GIF1; // clear flags + DMA1_CCR7 &= ~DMA_CCR_EN; // disable (what if it's enabled?) to set address + DMA1_CPAR7 = (uint32_t) &(TIM_CCR4(TIM2)); // dma_set_peripheral_address(DMA1, DMA_CHANNEL7, (uint32_t) &(TIM_CCR4(TIM2))); + DMA1_CMAR7 = (uint32_t) &tim2_buff[1]; // dma_set_memory_address(DMA1, DMA_CHANNEL7, (uint32_t)tim2_buff); + DMA1_CNDTR7 = tum2buff_ctr-1;//dma_set_number_of_data(DMA1, DMA_CHANNEL7, tum2buff_ctr); + // TIM2_CH4 - DMA1, channel 7 + dma_channel_reset(DMA1, DMA_CHANNEL1); + DMA1_CCR1 = DMA_CCR_MINC | DMA_CCR_PSIZE_16BIT | DMA_CCR_MSIZE_16BIT + | DMA_CCR_TEIE | DMA_CCR_TCIE | DMA_CCR_PL_HIGH; + DMA1_CPAR1 = (uint32_t) &(TIM_CCR3(TIM2)); //dma_set_peripheral_address(DMA1, DMA_CHANNEL1, (uint32_t) &(TIM_CCR3(TIM2))); + DMA1_CMAR1 = (uint32_t) tim2_inbuff; //dma_set_memory_address(DMA1, DMA_CHANNEL1, (uint32_t) tim2_inbuff); + DMA1_CNDTR1 = tum2buff_ctr; //dma_set_number_of_data(DMA1, DMA_CHANNEL1, tum2buff_ctr); + nvic_enable_irq(NVIC_DMA1_CHANNEL1_IRQ); + + DMA1_CCR7 |= DMA_CCR_EN; //dma_enable_channel(DMA1, DMA_CHANNEL7); + DMA1_CCR1 |= DMA_CCR_EN; //dma_enable_channel(DMA1, DMA_CHANNEL1); + + TIM2_SR = 0; // clear all flags + TIM2_ARR = BIT_LEN; // bit length + TIM2_CCR4 = tim2_buff[0]; // we should manually set first bit to avoid zero in tim2_inbuff[0] + TIM2_EGR = TIM_EGR_UG; // update value of ARR + TIM2_CR1 = TIM_CR1_ARPE; // bufferize ARR/CCR + + TIM2_CR2 &= ~TIM_CR2_CCDS; // timer_set_dma_on_compare_event(TIM2); + TIM2_DIER = TIM_DIER_CC4DE | TIM_DIER_CC3DE; // enable DMA events + // set low polarity, enable cc out & enable input capture + TIM2_CR1 |= TIM_CR1_CEN; // run timer +#ifdef EBUG + gpio_clear(GPIOC, GPIO10); +#endif + DBG("RUN transfer of "); + INT(tum2buff_ctr); + DBG(" bits\n"); +} + +uint16_t rstat = 0, lastcc3 = 3; +void ow_reset(){ + //init_ow_dmatimer(); + ow_done = 0; + rstat = 0; + TIM2_SR = 0; // clear all flags + TIM2_CR1 = 0; + TIM2_DIER = 0; // disable timer interrupts + TIM2_ARR = RESET_LEN; // set period to 1ms + TIM2_CCR4 = RESET_P; // zero pulse length + TIM2_EGR = TIM_EGR_UG; // update values of ARR & CCR4 + //TIM2_CCMR2 = TIM_CCMR2_OC4M_PWM1 | TIM_CCMR2_OC4PE | TIM_CCMR2_CC3S_IN_TI4; + //TIM2_CCER = TIM_CCER_CC4P | TIM_CCER_CC4E | TIM_CCER_CC3E; + DBG("OW RESET in process"); + TIM2_DIER = TIM_DIER_CC3IE; +#ifdef EBUG + gpio_clear(GPIOC, GPIO10); +#endif + TIM2_CR1 = TIM_CR1_OPM | TIM_CR1_CEN | TIM_CR1_UDIS; // we need only single pulse & run timer; disable UEV + TIM2_SR = 0; // clear update flag generated after timer's running + nvic_enable_irq(NVIC_TIM2_IRQ); +} + +void tim2_isr(){ + if(TIM2_SR & TIM_SR_UIF){ // update interrupt + TIM2_DIER = 0; // disable all timer interrupts +#ifdef EBUG + gpio_set(GPIOC, GPIO10); +#endif + TIM2_CCR4 = 0; // set output value to 1 + TIM2_SR = 0; // clear flag + nvic_disable_irq(NVIC_TIM2_IRQ); + ow_done = 1; + rstat = lastcc3; + DBG(" ... done!\n"); + } + if(TIM2_SR & TIM_SR_CC3IF){ // we need this interrupt to store CCR3 value + lastcc3 = TIM2_CCR3; + TIM2_CR1 &= ~TIM_CR1_UDIS; // enable UEV + TIM2_SR = 0; // clear flag (we've manage TIM_SR_UIF before, so can simply do =0) + TIM2_DIER |= TIM_DIER_UIE; // Now allow also Update interrupts to turn off everything + } +} + +/** + * DMA interrupt in 1-wire mode + */ +void dma1_channel1_isr(){ + int i; + if(DMA1_ISR & DMA_ISR_TCIF1){ +#ifdef EBUG + gpio_set(GPIOC, GPIO10); +#endif + DMA1_IFCR = DMA_IFCR_CTCIF1; + TIM2_CR1 &= ~TIM_CR1_CEN; // timer_disable_counter(TIM2); + DMA1_CCR1 &= ~DMA_CCR_EN; // disable DMA1 channel 1 + nvic_disable_irq(NVIC_DMA1_CHANNEL1_IRQ); + ow_done = 1; + for(i = 0; i < tum2buff_ctr; i++){ + print_int(tim2_inbuff[i]); + P(" "); + } + P("\n"); + }else if(DMA1_ISR & DMA_ISR_TEIF1){ + DMA1_IFCR = DMA_IFCR_CTEIF1; + DBG("DMA in transfer error\n"); + } +} + +void dma1_channel7_isr(){ + if(DMA1_ISR & DMA_ISR_TCIF7){ + DMA1_IFCR = DMA_IFCR_CTCIF7; // clear flag + DMA1_CCR7 &= ~DMA_CCR_EN; // disable DMA1 channel 7 + }else if(DMA1_ISR & DMA_ISR_TEIF7){ + DMA1_IFCR = DMA_IFCR_CTEIF7; + DBG("DMA out transfer error\n"); + } +} + + +uint8_t OW_get_reset_status(){ + if(rstat < RESET_BARRIER) return 0; // no devices + return 1; +} + + +uint8_t ow_data_ready = 0; // flag of reading OK + +/** + * Process 1-wire commands depending on its state + */ +void OW_process(){ + static uint8_t ow_was_reseting = 0; + switch(OW_State){ + case OW_OFF_STATE: + return; + break; + case OW_RESET_STATE: + DBG("OW reset\n"); + OW_State = OW_SEND_STATE; + ow_was_reseting = 1; + ow_reset(); + break; + case OW_SEND_STATE: + if(!ow_done) return; // reset in work + if(ow_was_reseting){ + if(rstat < RESET_BARRIER){ + ERR("Error: no 1-wire devices found"); + INT(rstat); + DBG("\n"); + ow_was_reseting = 0; + OW_State = OW_OFF_STATE; + return; + } + } + ow_was_reseting = 0; + OW_State = OW_READ_STATE; + run_dmatimer(); // turn on data transfer + DBG("OW send\n"); + break; + case OW_READ_STATE: + if(!ow_done) return; // data isn't ready + OW_State = OW_OFF_STATE; + // adc_dma_on(); // return DMA1_1 to ADC at end of data transmitting + if(ow_process_resdata){ + ow_process_resdata(); + ow_process_resdata = NULL; + } + ow_data_ready = 1; + DBG("OW read\n"); + break; + } +} + + +uint8_t *read_buf = NULL; // buffer for storing readed data +/** + * fill ID buffer with readed data + */ +void fill_buff_with_data(){ + if(!read_buf) return; + read_from_OWbuf(1, 8, read_buf); + int i, j; + // now check stored ROMs + for(i = 0; i < dev_amount; ++i){ + uint8_t *ROM = id_array[i].bytes; + for(j = 0; j < 8; j++) + if(ROM[j] != read_buf[j]) break; + if(j == 8){ // we found this cell + DBG("Such ID exists\n"); + goto ret; + } + } + ++dev_amount; +ret: + read_buf = NULL; +} + +/** + * fill Nth array with identificators + */ +//uint8_t comtosend = 0; +void OW_fill_next_ID(){ + if(dev_amount >= OW_MAX_NUM){ + ERR("No memory left for new device\n"); + return; + } + ow_data_ready = 0; + OW_State = OW_RESET_STATE; + OW_reset_buffer(); + OW_add_byte(OW_READ_ROM); + OW_add_read_seq(8); // wait for 8 bytes + read_buf = id_array[dev_amount].bytes; + ow_process_resdata = fill_buff_with_data; + DBG("wait for ID\n"); +} + +/** + * Procedure of 1-wire communications + * variables: + * @param sendReset - send RESET before transmission + * @param command - bytes sent to the bus (if we want to read, send OW_READ_SLOT) + * @param cLen - command buffer length (how many bytes to send) + * @return 1 if succeed, 0 if failure + */ +uint8_t OW_Send(uint8_t sendReset, uint8_t *command, uint8_t cLen){ + ow_data_ready = 0; + // if reset needed - send RESET and check bus + if(sendReset) + OW_State = OW_RESET_STATE; + else + OW_State = OW_SEND_STATE; + OW_reset_buffer(); + while(cLen-- > 0){ + if(!OW_add_byte(*command++)) return 0; + } + return 1; +} + +/** + * convert temperature from scratchpad + * in case of error return 200000 (ERR_TEMP_VAL) + * return value in 10th degrees centigrade + * + * 0 - themperature LSB + * 1 - themperature MSB (all higher bits are sign) + * 2 - T_H + * 3 - T_L + * 4 - B20: Configuration register (only bits 6/5 valid: 9..12 bits resolution); 0xff for S20 + * 5 - 0xff (reserved) + * 6 - (reserved for B20); S20: COUNT_REMAIN (0x0c) + * 7 - COUNT PER DEGR (0x10) + * 8 - CRC + */ +int32_t gettemp(uint8_t *scratchpad){ + // detect DS18S20 + int32_t t = 0; + uint8_t l,m; + int8_t v; + if(scratchpad[7] == 0xff) // 0xff can be only if there's no such device or some other error + return ERR_TEMP_VAL; + m = scratchpad[1]; + l = scratchpad[0]; + if(scratchpad[4] == 0xff){ // DS18S20 + v = l >> 1 | (m & 0x80); // take signum from MSB + t = ((int32_t)v) * 10L; + if(l&1) t += 5L; // decimal 0.5 + }else{ + v = l>>4 | ((m & 7)<<4) | (m & 0x80); + t = ((int32_t)v) * 10L; + m = l & 0x0f; // add decimal + t += (int32_t)m; // t = v*10 + l*1.25 -> convert + if(m > 1) ++t; // 1->1, 2->3, 3->4, 4->5, 5->6 + else if(m > 5) t += 2L; // 6->8, 7->9 + } + return t; +} + +int32_t temperature = ERR_TEMP_VAL; +int8_t Ncur = 0; +/** + * get temperature from buffer + */ +void convert_next_temp(){ + uint8_t scratchpad[9]; + if(dev_amount < 2){ + read_from_OWbuf(2, 9, scratchpad); + }else{ + read_from_OWbuf(10, 9, scratchpad); + } + temperature = gettemp(scratchpad); + DBG("Readed temperature: "); + INT(temperature); + DBG("/10 degrC\n"); +} + +/** + * read next stored thermometer + */ +void OW_read_next_temp(){ + ow_data_ready = 0; + OW_State = OW_RESET_STATE; + OW_reset_buffer(); + int i; + if(dev_amount < 2){ + Ncur = -1; + OW_add_byte(OW_SKIP_ROM); + }else{ + if(++Ncur >= dev_amount) Ncur = 0; + OW_add_byte(OW_MATCH_ROM); + uint8_t *ROM = id_array[Ncur].bytes; + for(i = 0; i < 8; ++i) + OW_add_byte(ROM[i]); + } + OW_add_byte(OW_READ_SCRATCHPAD); + OW_add_read_seq(9); // wait for 9 bytes - ROM + ow_process_resdata = convert_next_temp; +} + +void OW_send_read_seq(){ + ow_data_ready = 0; + OW_State = OW_RESET_STATE; + OW_reset_buffer(); + OW_add_byte(OW_SKIP_ROM); + OW_add_byte(OW_CONVERT_T); + ow_process_resdata = NULL; +} +/* + * scan 1-wire bus + * WARNING! The procedure works in real-time, so it is VERY LONG + * num - max number of devices + * buf - array for devices' ID's (8*num bytes) + * return amount of founded devices + * +uint8_t OW_Scan(uint8_t *buf, uint8_t num){ + unsigned long path,next,pos; + uint8_t bit,chk; + uint8_t cnt_bit, cnt_byte, cnt_num; + path=0; + cnt_num=0; + do{ + //(issue the 'ROM search' command) + if( 0 == OW_WriteCmd(OW_SEARCH_ROM) ) return 0; + OW_Wait_TX(); + OW_ClearBuff(); // clear RX buffer + next = 0; // next path to follow + pos = 1; // path bit pointer + for(cnt_byte = 0; cnt_byte != 8; cnt_byte++){ + buf[cnt_num*8 + cnt_byte] = 0; + for(cnt_bit = 0; cnt_bit != 8; cnt_bit++){ + //(read two bits, 'bit' and 'chk', from the 1-wire bus) + OW_SendBits(OW_R, 2); + OW_Wait_TX(); + bit = -----OW_ReadByte(); + chk = bit & 0x02; // bit 1 + bit = bit & 0x01; // bit 0 + if(bit && chk) return 0; // error + if(!bit && !chk){ // collision, both are zero + if (pos & path) bit = 1; // if we've been here before + else next = (path&(pos-1)) | pos; // else, new branch for next + pos <<= 1; + } + //(save this bit as part of the current ROM value) + if (bit) buf[cnt_num*8 + cnt_byte]|=(1<550 if there's devices on line (on reset), >12 (typ.15) - read 0, < 12 (typ.1) - read 1 +#define RESET_LEN ((uint16_t)1000) +#define BIT_LEN ((uint16_t)100) +#define RESET_P ((uint16_t)500) +#define BIT_ONE_P ((uint16_t)10) +#define BIT_ZERO_P ((uint16_t)60) +#define BIT_READ_P ((uint16_t)5) +#define RESET_BARRIER ((uint16_t)550) +#define ONE_ZERO_BARRIER ((uint16_t)10) + +#define ERR_TEMP_VAL (200000) + +typedef struct{ + uint8_t bytes[8]; +} OW_ID; + +extern OW_ID id_array[]; + +#define OW_MAX_NUM 8 + +void init_ow_dmatimer(); +void run_dmatimer(); +extern uint8_t ow_done; +#define OW_READY() (ow_done) +void ow_dma_on(); +uint8_t OW_add_byte(uint8_t ow_byte); +uint8_t OW_add_read_seq(uint8_t Nbytes); +void read_from_OWbuf(uint8_t start_idx, uint8_t N, uint8_t *outbuf); +void ow_reset(); +uint8_t OW_get_reset_status(); + +extern int tum2buff_ctr; +#define OW_reset_buffer() do{tum2buff_ctr = 0;}while(0) + +extern uint8_t ow_data_ready; +#define OW_DATA_READY() (ow_data_ready) +#define OW_CLEAR_READY_FLAG() do{ow_data_ready = 0;}while(0) + +void OW_process(); +void OW_fill_next_ID(); +void OW_send_read_seq(); +uint8_t OW_Send(uint8_t sendReset, uint8_t *command, uint8_t cLen); + +extern int32_t temperature; +extern int8_t Ncur; +void OW_read_next_temp(); +#define OW_current_temp() (temperature) +#define OW_current_num() (Ncur) + +/* + * thermometer commands + * send them with bus reset! + */ +// find devices +#define OW_SEARCH_ROM (0xf0) +// read device (when it is alone on the bus) +#define OW_READ_ROM (0x33) +// send device ID (after this command - 8 bytes of ID) +#define OW_MATCH_ROM (0x55) +// broadcast command +#define OW_SKIP_ROM (0xcc) +// find devices with critical conditions +#define OW_ALARM_SEARCH (0xec) +/* + * thermometer functions + * send them without bus reset! + */ +// start themperature reading +#define OW_CONVERT_T (0x44) +// write critical temperature to device's RAM +#define OW_SCRATCHPAD (0x4e) +// read whole device flash +#define OW_READ_SCRATCHPAD (0xbe) +// copy critical themperature from device's RAM to its EEPROM +#define OW_COPY_SCRATCHPAD (0x48) +// copy critical themperature from EEPROM to RAM (when power on this operation runs automatically) +#define OW_RECALL_E2 (0xb8) +// check whether there is devices wich power up from bus +#define OW_READ_POWER_SUPPLY (0xb4) + + +/* + * thermometer identificator is: 8bits CRC, 48bits serial, 8bits device code (10h) + * Critical temperatures is T_H and T_L + * T_L is lowest allowed temperature + * T_H is highest -//- + * format T_H and T_L: 1bit sigh + 7bits of data + */ + + +/* + * RAM register: + * 0 - themperature: 1 ADU == 0.5 degrC + * 1 - sign (0 - T>0 degrC ==> T=byte0; 1 - T<0 degrC ==> T=byte0-0xff+1) + * 2 - T_H + * 3 - T_L + * 4 - 0xff (reserved) + * 5 - 0xff (reserved) + * 6 - COUNT_REMAIN (0x0c) + * 7 - COUNT PER DEGR (0x10) + * 8 - CRC + */ + + +#endif // __ONEWIRE_H__ diff --git a/1_wire/sync.c b/1_wire/sync.c new file mode 100644 index 0000000..ba688c3 --- /dev/null +++ b/1_wire/sync.c @@ -0,0 +1,93 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Fergus Noble + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* + * TODO: + * implement mutexes for other type of MCU (which doesn't have strex & ldrex) + */ + +#include + +/* DMB is supported on CM0 */ +void __dmb() +{ + __asm__ volatile ("dmb"); +} + +/* Those are defined only on CM3 or CM4 */ +#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) + +uint32_t __ldrex(volatile uint32_t *addr) +{ + uint32_t res; + __asm__ volatile ("ldrex %0, [%1]" : "=r" (res) : "r" (addr)); + return res; +} + +uint32_t __strex(uint32_t val, volatile uint32_t *addr) +{ + uint32_t res; + __asm__ volatile ("strex %0, %2, [%1]" + : "=&r" (res) : "r" (addr), "r" (val)); + return res; +} + +void mutex_lock(mutex_t *m) +{ + uint32_t status = 0; + + do { + /* Wait until the mutex is unlocked. */ + while (__ldrex(m) != MUTEX_UNLOCKED); + + /* Try to acquire it. */ + status = __strex(MUTEX_LOCKED, m); + + /* Did we get it? If not then try again. */ + } while (status != 0); + + /* Execute the mysterious Data Memory Barrier instruction! */ + __dmb(); +} + +void mutex_unlock(mutex_t *m) +{ + /* Ensure accesses to protected resource are finished */ + __dmb(); + + /* Free the lock. */ + *m = MUTEX_UNLOCKED; +} + +/* + * Try to lock mutex + * if it's already locked or there was error in STREX, return MUTEX_LOCKED + * else return MUTEX_UNLOCKED + */ +mutex_t mutex_trylock(mutex_t *m){ + uint32_t status = 0; + mutex_t old_lock = __ldrex(m); // get mutex value + // set mutex + status = __strex(MUTEX_LOCKED, m); + if(status == 0) __dmb(); + else old_lock = MUTEX_LOCKED; + return old_lock; +} + +#endif diff --git a/1_wire/sync.h b/1_wire/sync.h new file mode 100644 index 0000000..bfe837b --- /dev/null +++ b/1_wire/sync.h @@ -0,0 +1,53 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Fergus Noble + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef LIBOPENCM3_CM3_SYNC_H +#define LIBOPENCM3_CM3_SYNC_H + +void __dmb(void); + +/* Implements synchronisation primitives as discussed in the ARM document + * DHT0008A (ID081709) "ARM Synchronization Primitives" and the ARM v7-M + * Architecture Reference Manual. +*/ + +/* --- Exclusive load and store instructions ------------------------------- */ + +/* Those are defined only on CM3 or CM4 */ +#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) + +uint32_t __ldrex(volatile uint32_t *addr); +uint32_t __strex(uint32_t val, volatile uint32_t *addr); + +/* --- Convenience functions ----------------------------------------------- */ + +/* Here we implement some simple synchronisation primitives. */ + +typedef uint32_t mutex_t; + +#define MUTEX_UNLOCKED 0 +#define MUTEX_LOCKED 1 + +void mutex_lock(mutex_t *m); +void mutex_unlock(mutex_t *m); +mutex_t mutex_trylock(mutex_t *m); + +#endif + +#endif diff --git a/1_wire/user_proto.c b/1_wire/user_proto.c new file mode 100644 index 0000000..1367a08 --- /dev/null +++ b/1_wire/user_proto.c @@ -0,0 +1,240 @@ +/* + * user_proto.c + * + * Copyright 2014 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "cdcacm.h" +#include "main.h" +#include "hardware_ini.h" +#include "onewire.h" + +// integer value given by user +static volatile int32_t User_value = 0; +enum{ + UVAL_START, // user start to write integer value + UVAL_ENTERED, // value entered but not printed + UVAL_BAD // entered bad value +}; +uint8_t Uval_ready = UVAL_BAD; + +int read_int(char *buf, int cnt); + +intfun I = NULL; // function to process entered integer + +#define READINT() do{i += read_int(&buf[i+1], len-i-1);}while(0) + +void help(){ + P("H\tshow this help\n"); + P("I\ttest entering integer value\n"); + P("T\tshow current approx. time\n"); + P("1\tswitch LED D1 state\n"); + P("2\tswitch LED D2 state\n"); + P("R\tstart reading temperature\n"); + P("P\tread DS18 ID\n"); + P("Q\tget temperature\n"); +} + +/** + * show entered integer value + */ +uint8_t show_int(int32_t v){ + newline(); + print_int(v); + newline(); + return 0; +} + +/** + * parce command buffer buf with length len + * return 0 if buffer processed or len if there's not enough data in buffer + */ +int parce_incoming_buf(char *buf, int len){ + uint8_t command; + //uint32_t utmp; + int i = 0; + if(Uval_ready == UVAL_START){ // we are in process of user's value reading + i += read_int(buf, len); + } + if(Uval_ready == UVAL_ENTERED){ + //print_int(User_value); // printout readed integer value for error control + Uval_ready = UVAL_BAD; // clear Uval + I(User_value); + return 0; + } + for(; i < len; i++){ + command = buf[i]; + if(!command) continue; // omit zero + switch (command){ + case '1': + gpio_toggle(LEDS_PORT, LED_D1_PIN); + break; + case '2': + gpio_toggle(LEDS_PORT, LED_D2_PIN); + break; + case 'H': // show help + help(); + break; + case 'I': // enter integer & show its value + I = show_int; + READINT(); + break; + case 'T': + newline(); + print_int(Timer); // be careful for Time >= 2^{31}!!! + newline(); + break; + case 'P': + OW_fill_next_ID(); + break; + case 'Q': + OW_read_next_temp(); + break; + case 'R': + OW_send_read_seq(); + break; + case '\n': // show newline, space and tab as is + case '\r': + case ' ': + case '\t': + break; + default: + command = '?'; // echo '?' on unknown command in byte mode + } + usb_send(command); // echo readed byte + } + return 0; // all data processed - 0 bytes leave in buffer +} + +/** + * Send char array wrd thru USB or UART + */ +void prnt(uint8_t *wrd){ + if(!wrd) return; + while(*wrd) usb_send(*wrd++); +} + +void ERR(char *wrd){ + if(!wrd) return; + while(*wrd) usb_send(*((uint8_t*)wrd++)); + usb_send('\n'); +} + +/** + * Read from TTY integer value given by user (in DEC). + * Reading stops on first non-numeric symbol. + * To work with symbol terminals reading don't stops on buffer's end, + * it waits for first non-numeric char. + * When working on string terminals, terminate string by '\n', 0 or any other symbol + * @param buf - buffer to read from + * @param cnt - buffer length + * @return amount of readed symbols + */ +int read_int(char *buf, int cnt){ + int readed = 0, i; + static int enteredDigits; // amount of entered digits + static int sign; // sign of readed value + if(Uval_ready){ // this is first run + Uval_ready = UVAL_START; // clear flag + enteredDigits = 0; // 0 digits entered + User_value = 0; // clear value + sign = 1; // clear sign + } + if(!cnt) return 0; + for(i = 0; i < cnt; i++, readed++){ + uint8_t chr = buf[i]; + if(chr == '-'){ + if(enteredDigits == 0){ // sign should be first + sign = -1; + continue; + }else{ // '-' after number - reject entered value + Uval_ready = UVAL_BAD; + break; + } + } + if(chr < '0' || chr > '9'){ + if(enteredDigits) + Uval_ready = UVAL_ENTERED; + else + Uval_ready = UVAL_BAD; // bad symbol + break; + } + User_value = User_value * 10 + (int32_t)(chr - '0'); + enteredDigits++; + } + if(Uval_ready == UVAL_ENTERED) // reading has met an non-numeric character + User_value *= sign; + return readed; +} + +/** + * Print buff as hex values + * @param buf - buffer to print + * @param l - buf length + * @param s - function to send a byte + */ +void print_hex(uint8_t *buff, uint8_t l){ + void putc(uint8_t c){ + if(c < 10) + usb_send(c + '0'); + else + usb_send(c + 'a' - 10); + } + usb_send('0'); usb_send('x'); // prefix 0x + while(l--){ + putc(buff[l] >> 4); + putc(buff[l] & 0x0f); + } +} + +/** + * Print decimal integer value + * @param N - value to print + * @param s - function to send a byte + */ +void print_int(int32_t N){ + uint8_t buf[10], L = 0; + if(N < 0){ + usb_send('-'); + N = -N; + } + if(N){ + while(N){ + buf[L++] = N % 10 + '0'; + N /= 10; + } + while(L--) usb_send(buf[L]); + }else usb_send('0'); +} + +void OW_printID(uint8_t N){ + void putc(uint8_t c){ + if(c < 10) + usb_send(c + '0'); + else + usb_send(c + 'a' - 10); + } + int i; + uint8_t *b = id_array[N].bytes; + usb_send('0'); usb_send('x'); // prefix 0x + for(i = 0; i < 8; i++){ + putc(b[i] >> 4); + putc(b[i] & 0x0f); + } + usb_send('\n'); +} diff --git a/1_wire/user_proto.h b/1_wire/user_proto.h new file mode 100644 index 0000000..c3c6229 --- /dev/null +++ b/1_wire/user_proto.h @@ -0,0 +1,51 @@ +/* + * user_proto.h + * + * Copyright 2014 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#pragma once +#ifndef __USER_PROTO_H__ +#define __USER_PROTO_H__ + +#include "cdcacm.h" + +// shorthand for prnt +#define P(arg) do{prnt((uint8_t*)arg);}while(0) +// debug message - over USB +#ifdef EBUG + #define DBG(a) do{prnt((uint8_t*)a);}while(0) + #define INT(N) do{print_int(N);}while(0) +#else + #define DBG(a) + #define INT(N) +#endif + +typedef uint8_t (*intfun)(int32_t); + +void ERR(char *wrd); +void prnt(uint8_t *wrd); +#define newline() usb_send('\n') + +void print_int(int32_t N); +void print_hex(uint8_t *buff, uint8_t l); + +int parce_incoming_buf(char *buf, int len); +void OW_printID(uint8_t N); + +#endif // __USER_PROTO_H__ diff --git a/simple_cdc/hardware_ini.c b/simple_cdc/hardware_ini.c index 262a692..ee3e0d7 100644 --- a/simple_cdc/hardware_ini.c +++ b/simple_cdc/hardware_ini.c @@ -69,17 +69,26 @@ void SysTick_init(){ void check_btns(){ static uint8_t oldstate[2] = {1,1}; // old buttons state uint8_t newstate[2], i; + static uint32_t Old_timer[2] = {0,0}; newstate[0] = gpio_get(BTNS_PORT, BTN_S2_PIN) ? 1 : 0; newstate[1] = gpio_get(BTNS_PORT, BTN_S3_PIN) ? 1 : 0; for(i = 0; i < 2; i++){ uint8_t new = newstate[i]; - if(new != oldstate[i]){ - P("Button S"); - usb_send('2' + i); - if(new) P("pressed"); - else P("released"); - newline(); - oldstate[i] = new; + // pause for 60ms + uint32_t O = Old_timer[i]; + if(!O){ + if(Timer - O > 60 || O > Timer){ + P("Button S"); + usb_send('2' + i); + if(new) P("released"); + else P("pressed"); + newline(); + oldstate[i] = new; + Old_timer[i] = 0; + } + } + else if(new != oldstate[i]){ + Old_timer[i] = Timer; } } } diff --git a/simple_cdc/usb_cdc_simple.bin b/simple_cdc/usb_cdc_simple.bin index e78d8fb1fb1d65c34f970afc77c480f0e57c81ff..7d1b12386986de1e54e7e5214ab8f8fd1aaf80aa 100755 GIT binary patch delta 33 pcmX?Ma>8W878b_4o42wki0~E^r4|>brZ5zx=A8W878b^Po42wki0~Gr=A