diff --git a/DRUM/Makefile b/DRUM/Makefile new file mode 100644 index 0000000..8245c45 --- /dev/null +++ b/DRUM/Makefile @@ -0,0 +1,34 @@ +NAME=testproj +SDCC=sdcc + +CCFLAGS=-DSTM8S105 -I../ -I/usr/share/sdcc/include -mstm8 --out-fmt-ihx -DUART +LDFLAGS= -mstm8 --out-fmt-ihx -lstm8 +FLASHFLAGS=-cstlinkv2 -pstm8s105 + +SRC=$(wildcard *.c) +# ATTENTION: FIRST in list should be file with main() +OBJ=$(SRC:%.c=%.rel) +TRASH=$(OBJ) $(SRC:%.c=%.rst) $(SRC:%.c=%.asm) $(SRC:%.c=%.lst) +TRASH+=$(SRC:%.c=%.sym) $(NAME).ihx $(NAME).lk $(NAME).map +INDEPENDENT_HEADERS=../stm8l.h ports_definition.h Makefile + +all: $(NAME).ihx + +$(SRC) : %.c : %.h $(INDEPENDENT_HEADERS) + @touch $@ + +%.h: ; + +clean: + rm -f $(TRASH) + +load: $(NAME).ihx + stm8flash $(FLASHFLAGS) -w $(NAME).ihx + +%.rel: %.c + $(SDCC) $(CCFLAGS) -c $< + +$(NAME).ihx: $(OBJ) + $(SDCC) $(LDFLAGS) $(OBJ) -o $(NAME).ihx + +.PHONY: all diff --git a/DRUM/README b/DRUM/README new file mode 100644 index 0000000..c5f02b8 --- /dev/null +++ b/DRUM/README @@ -0,0 +1 @@ +This is a table-based generator of simplest waveforms diff --git a/DRUM/interrupts.c b/DRUM/interrupts.c new file mode 100644 index 0000000..aa6dd7e --- /dev/null +++ b/DRUM/interrupts.c @@ -0,0 +1,182 @@ +/* + * interrupts.c + * + * Copyright 2014 Edward V. Emelianoff + * + * 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 "ports_definition.h" +#include "main.h" +#include "noicegen.h" + +// Top Level Interrupt +INTERRUPT_HANDLER(TLI_IRQHandler, 0){} + +// Auto Wake Up Interrupt +INTERRUPT_HANDLER(AWU_IRQHandler, 1){} + +// Clock Controller Interrupt +INTERRUPT_HANDLER(CLK_IRQHandler, 2){} + +// External Interrupt PORTA +INTERRUPT_HANDLER(EXTI_PORTA_IRQHandler, 3){ + +} + +// External Interrupt PORTB +INTERRUPT_HANDLER(EXTI_PORTB_IRQHandler, 4){ + +} + +// External Interrupt PORTC +INTERRUPT_HANDLER(EXTI_PORTC_IRQHandler, 5){ + +} + +// External Interrupt PORTD +INTERRUPT_HANDLER(EXTI_PORTD_IRQHandler, 6){ + +} + +// External Interrupt PORTE +INTERRUPT_HANDLER(EXTI_PORTE_IRQHandler, 7){ + +} + +#ifdef STM8S903 +// External Interrupt PORTF +INTERRUPT_HANDLER(EXTI_PORTF_IRQHandler, 8){} +#endif // STM8S903 + +#if defined (STM8S208) || defined (STM8AF52Ax) +// CAN RX Interrupt routine. +INTERRUPT_HANDLER(CAN_RX_IRQHandler, 8){} + +// CAN TX Interrupt routine. +INTERRUPT_HANDLER(CAN_TX_IRQHandler, 9){} +#endif // STM8S208 || STM8AF52Ax + +// SPI Interrupt routine. +INTERRUPT_HANDLER(SPI_IRQHandler, 10){} + +// Timer1 Update/Overflow/Trigger/Break Interrupt +INTERRUPT_HANDLER(TIM1_UPD_OVF_TRG_BRK_IRQHandler, 11){ +} + +// Timer1 Capture/Compare Interrupt routine. +INTERRUPT_HANDLER(TIM1_CAP_COM_IRQHandler, 12){} + +#ifdef STM8S903 +// Timer5 Update/Overflow/Break/Trigger Interrupt +INTERRUPT_HANDLER(TIM5_UPD_OVF_BRK_TRG_IRQHandler, 13){} + +// Timer5 Capture/Compare Interrupt +INTERRUPT_HANDLER(TIM5_CAP_COM_IRQHandler, 14){} + +#else // STM8S208, STM8S207, STM8S105 or STM8S103 or STM8AF62Ax or STM8AF52Ax or STM8AF626x + +// Timer2 Update/Overflow/Break Interrupt +INTERRUPT_HANDLER(TIM2_UPD_OVF_BRK_IRQHandler, 13){ // generate pulses for stepper CLK + if(TIM2_SR1 & TIM_SR1_UIF){ + sample_flag = 1; + TIM2_SR1 &= ~TIM_SR1_UIF; + } +} + +// Timer2 Capture/Compare Interrupt +INTERRUPT_HANDLER(TIM2_CAP_COM_IRQHandler, 14){ +} +#endif // STM8S903 + +#if defined (STM8S208) || defined(STM8S207) || defined(STM8S007) || defined(STM8S105) || \ + defined(STM8S005) || defined (STM8AF62Ax) || defined (STM8AF52Ax) || defined (STM8AF626x) +// Timer3 Update/Overflow/Break Interrupt +INTERRUPT_HANDLER(TIM3_UPD_OVF_BRK_IRQHandler, 15){ + +} + +// Timer3 Capture/Compare Interrupt +INTERRUPT_HANDLER(TIM3_CAP_COM_IRQHandler, 16){} +#endif // STM8S208, STM8S207 or STM8S105 or STM8AF62Ax or STM8AF52Ax or STM8AF626x + +#if defined (STM8S208) || defined(STM8S207) || defined(STM8S007) || defined(STM8S103) || \ + defined(STM8S003) || defined (STM8AF62Ax) || defined (STM8AF52Ax) || defined (STM8S903) +// UART1 TX Interrupt +INTERRUPT_HANDLER(UART1_TX_IRQHandler, 17){} + +// UART1 RX Interrupt +INTERRUPT_HANDLER(UART1_RX_IRQHandler, 18){} +#endif // STM8S208 or STM8S207 or STM8S103 or STM8S903 or STM8AF62Ax or STM8AF52Ax + +// I2C Interrupt +INTERRUPT_HANDLER(I2C_IRQHandler, 19){} + +#if defined(STM8S105) || defined(STM8S005) || defined (STM8AF626x) +// UART2 TX interrupt +INTERRUPT_HANDLER(UART2_TX_IRQHandler, 20){} + +// UART2 RX interrupt +INTERRUPT_HANDLER(UART2_RX_IRQHandler, 21){ +#ifdef UART + U8 rb; + if(UART2_SR & UART_SR_RXNE){ // data received + rb = UART2_DR; // read received byte & clear RXNE flag + while(!(UART2_SR & UART_SR_TXE)); + UART_send_byte(rb); // echo received symbol + UART_rx[UART_rx_cur_i++] = rb; // put received byte into cycled buffer + if(UART_rx_cur_i == UART_rx_start_i){ // Oops: buffer overflow! Just forget old data + UART_rx_start_i++; + check_UART_pointer(UART_rx_start_i); + } + check_UART_pointer(UART_rx_cur_i); + } +#endif +} +#endif // STM8S105 or STM8AF626x + +#if defined(STM8S207) || defined(STM8S007) || defined(STM8S208) || defined (STM8AF52Ax) || defined (STM8AF62Ax) +// UART3 TX interrupt +INTERRUPT_HANDLER(UART3_TX_IRQHandler, 20){} + +// UART3 RX interrupt +INTERRUPT_HANDLER(UART3_RX_IRQHandler, 21){} +#endif // STM8S208 or STM8S207 or STM8AF52Ax or STM8AF62Ax + +#if defined(STM8S207) || defined(STM8S007) || defined(STM8S208) || defined (STM8AF52Ax) || defined (STM8AF62Ax) +// ADC2 interrupt +INTERRUPT_HANDLER(ADC2_IRQHandler, 22){} +#else +// ADC1 interrupt +INTERRUPT_HANDLER(ADC1_IRQHandler, 22){ +} +#endif // STM8S208 or STM8S207 or STM8AF52Ax or STM8AF62Ax + +#ifdef STM8S903 +// Timer6 Update/Overflow/Trigger Interrupt +INTERRUPT_HANDLER(TIM6_UPD_OVF_TRG_IRQHandler, 23){} +#else // STM8S208, STM8S207, STM8S105 or STM8S103 or STM8AF52Ax or STM8AF62Ax or STM8AF626x +// Timer4 Update/Overflow Interrupt +INTERRUPT_HANDLER(TIM4_UPD_OVF_IRQHandler, 23){ + if(TIM4_SR & TIM_SR1_UIF){ // update interrupt + Global_time++; // increase timer + } + TIM4_SR = 0; // clear all interrupt flags +} +#endif // STM8S903 + +// Eeprom EEC Interrupt +INTERRUPT_HANDLER(EEPROM_EEC_IRQHandler, 24){} diff --git a/DRUM/interrupts.h b/DRUM/interrupts.h new file mode 100644 index 0000000..6edf384 --- /dev/null +++ b/DRUM/interrupts.h @@ -0,0 +1,144 @@ +/* + * interrupts.h + * + * Copyright 2014 Edward V. Emelianoff + * + * 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 __INTERRUPTS_H__ +#define __INTERRUPTS_H__ + +#include "stm8l.h" + +// Top Level Interrupt +INTERRUPT_DEFINITION(TLI_IRQHandler, 0); + +// Auto Wake Up Interrupt +INTERRUPT_DEFINITION(AWU_IRQHandler, 1); + +// Clock Controller Interrupt +INTERRUPT_DEFINITION(CLK_IRQHandler, 2); + +// External Interrupt PORTA +INTERRUPT_DEFINITION(EXTI_PORTA_IRQHandler, 3); + +// External Interrupt PORTB +INTERRUPT_DEFINITION(EXTI_PORTB_IRQHandler, 4); + +// External Interrupt PORTC +INTERRUPT_DEFINITION(EXTI_PORTC_IRQHandler, 5); + +// External Interrupt PORTD +INTERRUPT_DEFINITION(EXTI_PORTD_IRQHandler, 6); + +// External Interrupt PORTE +INTERRUPT_DEFINITION(EXTI_PORTE_IRQHandler, 7); + +#ifdef STM8S903 +// External Interrupt PORTF +INTERRUPT_DEFINITION(EXTI_PORTF_IRQHandler, 8); +#endif // STM8S903 + +#if defined (STM8S208) || defined (STM8AF52Ax) +// CAN RX Interrupt routine. +INTERRUPT_DEFINITION(CAN_RX_IRQHandler, 8); + +// CAN TX Interrupt routine. +INTERRUPT_DEFINITION(CAN_TX_IRQHandler, 9); +#endif // STM8S208 || STM8AF52Ax + +// SPI Interrupt routine. +INTERRUPT_DEFINITION(SPI_IRQHandler, 10); + +// Timer1 Update/Overflow/Trigger/Break Interrupt +INTERRUPT_DEFINITION(TIM1_UPD_OVF_TRG_BRK_IRQHandler, 11); + +// Timer1 Capture/Compare Interrupt routine. +INTERRUPT_DEFINITION(TIM1_CAP_COM_IRQHandler, 12); + +#ifdef STM8S903 +// Timer5 Update/Overflow/Break/Trigger Interrupt +INTERRUPT_DEFINITION(TIM5_UPD_OVF_BRK_TRG_IRQHandler, 13); + +// Timer5 Capture/Compare Interrupt +INTERRUPT_DEFINITION(TIM5_CAP_COM_IRQHandler, 14); + +#else // STM8S208, STM8S207, STM8S105 or STM8S103 or STM8AF62Ax or STM8AF52Ax or STM8AF626x +// Timer2 Update/Overflow/Break Interrupt +INTERRUPT_DEFINITION(TIM2_UPD_OVF_BRK_IRQHandler, 13); + +// Timer2 Capture/Compare Interrupt +INTERRUPT_DEFINITION(TIM2_CAP_COM_IRQHandler, 14); +#endif // STM8S903 + +#if defined (STM8S208) || defined(STM8S207) || defined(STM8S007) || defined(STM8S105) || \ + defined(STM8S005) || defined (STM8AF62Ax) || defined (STM8AF52Ax) || defined (STM8AF626x) +// Timer3 Update/Overflow/Break Interrupt +INTERRUPT_DEFINITION(TIM3_UPD_OVF_BRK_IRQHandler, 15); + +// Timer3 Capture/Compare Interrupt +INTERRUPT_DEFINITION(TIM3_CAP_COM_IRQHandler, 16); +#endif // STM8S208, STM8S207 or STM8S105 or STM8AF62Ax or STM8AF52Ax or STM8AF626x + +#if defined (STM8S208) || defined(STM8S207) || defined(STM8S007) || defined(STM8S103) || \ + defined(STM8S003) || defined (STM8AF62Ax) || defined (STM8AF52Ax) || defined (STM8S903) +// UART1 TX Interrupt +INTERRUPT_DEFINITION(UART1_TX_IRQHandler, 17); + +// UART1 RX Interrupt +INTERRUPT_DEFINITION(UART1_RX_IRQHandler, 18); +#endif // STM8S208 or STM8S207 or STM8S103 or STM8S903 or STM8AF62Ax or STM8AF52Ax + +// I2C Interrupt +INTERRUPT_DEFINITION(I2C_IRQHandler, 19); + +#if defined(STM8S105) || defined(STM8S005) || defined (STM8AF626x) +// UART2 TX interrupt +INTERRUPT_DEFINITION(UART2_TX_IRQHandler, 20); + +// UART2 RX interrupt +INTERRUPT_DEFINITION(UART2_RX_IRQHandler, 21); +#endif // STM8S105 or STM8AF626x + +#if defined(STM8S207) || defined(STM8S007) || defined(STM8S208) || defined (STM8AF52Ax) || defined (STM8AF62Ax) +// UART3 TX interrupt +INTERRUPT_DEFINITION(UART3_TX_IRQHandler, 20); + +// UART3 RX interrupt +INTERRUPT_DEFINITION(UART3_RX_IRQHandler, 21); +#endif // STM8S208 or STM8S207 or STM8AF52Ax or STM8AF62Ax + +#if defined(STM8S207) || defined(STM8S007) || defined(STM8S208) || defined (STM8AF52Ax) || defined (STM8AF62Ax) +// ADC2 interrupt +INTERRUPT_DEFINITION(ADC2_IRQHandler, 22); +#else // STM8S105, STM8S103 or STM8S903 or STM8AF626x +// ADC1 interrupt +INTERRUPT_DEFINITION(ADC1_IRQHandler, 22); +#endif // STM8S208 or STM8S207 or STM8AF52Ax or STM8AF62Ax + +#ifdef STM8S903 +// Timer6 Update/Overflow/Trigger Interrupt +INTERRUPT_DEFINITION(TIM6_UPD_OVF_TRG_IRQHandler, 23); +#else // STM8S208, STM8S207, STM8S105 or STM8S103 or STM8AF52Ax or STM8AF62Ax or STM8AF626x +// Timer4 Update/Overflow Interrupt +INTERRUPT_DEFINITION(TIM4_UPD_OVF_IRQHandler, 23); +#endif // STM8S903 + +// Eeprom EEC Interrupt +INTERRUPT_DEFINITION(EEPROM_EEC_IRQHandler, 24); + +#endif // __INTERRUPTS_H__ diff --git a/DRUM/main.c b/DRUM/main.c new file mode 100644 index 0000000..a27675e --- /dev/null +++ b/DRUM/main.c @@ -0,0 +1,267 @@ +/* + * blinky.c + * + * Copyright 2014 Edward V. Emelianoff + * + * 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 "stm8l.h" +#include "ports_definition.h" +#include "interrupts.h" +#include "main.h" +#include "noicegen.h" + +/* + * 0 0000 + * 1 0001 + * 2 0010 + * 3 0011 + * 4 0100 + * 5 0101 + * 6 0110 + * 7 0111 + * 8 1000 + * 9 1001 + * a 1010 + * b 1011 + * c 1100 + * d 1101 + * e 1110 + * f 1111 + */ + +unsigned long Global_time = 0L, boom_start = 0L; // global time in ms +unsigned int boom_length = 100; // length of "boom" in ms +U16 paused_val = 500; // interval between LED flashing +U8 snd_i = 0, bank_i = 0; // number of sample in sound, number in sine vawe +U8 sample_flag = 0; // flag is set in interrupt -> next sample in sound + +#ifdef UART +U8 UART_rx[UART_BUF_LEN]; // cycle buffer for received data +U8 UART_rx_start_i = 0; // started index of received data (from which reading starts) +U8 UART_rx_cur_i = 0; // index of current first byte in rx array (to which data will be written) +U8 UART_is_our = 0; // ==1 if we get UART +// ATTENTION! to change global variable in PROGRAM memory, it should be CONST!!! +const U8 UART_devNUM = THIS_DEVICE_NUM; // device number, master sais it + +/** + * Send one byte through UART + * @param byte - data to send + */ +void UART_send_byte(U8 byte){ + UART2_DR = byte; + while(!(UART2_SR & UART_SR_TC)); +} + +void uart_write(char *str){ + while(*str){ + UART2_DR = *str++; + while(!(UART2_SR & UART_SR_TC)); + } +} + +/** + * Read one byte from Rx buffer + * @param byte - where to store readed data + * @return 1 in case of non-empty buffer + */ +U8 UART_read_byte(U8 *byte){ + if(UART_rx_start_i == UART_rx_cur_i) // buffer is empty + return 0; + *byte = UART_rx[UART_rx_start_i++]; + check_UART_pointer(UART_rx_start_i); + return 1; +} + +void printUint(U8 *val, U8 len){ + unsigned long Number = 0; + U8 i = len; + char ch; + U8 decimal_buff[12]; // max len of U32 == 10 + \n + \0 + if(len > 4 || len == 3 || len == 0) return; + for(i = 0; i < 12; i++) + decimal_buff[i] = 0; + decimal_buff[10] = '\n'; + ch = 9; + switch(len){ + case 1: + Number = *((U8*)val); + break; + case 2: + Number = *((U16*)val); + break; + case 4: + Number = *((unsigned long*)val); + break; + } + do{ + i = Number % 10L; + decimal_buff[ch--] = i + '0'; + Number /= 10L; + }while(Number && ch > -1); + uart_write((char*)&decimal_buff[ch+1]); +} + +U8 readInt(int *val){ + unsigned long T = Global_time; + unsigned long R = 0; + int readed; + U8 sign = 0, rb, ret = 0, bad = 0; + do{ + if(!UART_read_byte(&rb)) continue; + if(rb == '-' && R == 0){ // negative number + sign = 1; + continue; + } + if(rb < '0' || rb > '9') break; // number ends with any non-digit symbol that will be omitted + ret = 1; // there's at least one digit + R = R * 10L + rb - '0'; + if(R > 0x7fff){ // bad value + R = 0; + bad = 0; + } + }while(Global_time - T < 10000); // wait no longer than 10s + if(bad || !ret) return 0; + readed = (int) R; + if(sign) readed *= -1; + *val = readed; + return 1; +} + + +void error_msg(char *msg){ + uart_write("\nERROR: "); + uart_write(msg); + UART_send_byte('\n'); +} +#endif // UART + + +int main() { + unsigned long T = 0L; + unsigned int I; + U8 cur_vol; + int Ival; +#ifdef UART + U8 rb; +#endif + CFG_GCR |= 1; // disable SWIM + // Configure clocking + CLK_CKDIVR = 0; // F_HSI = 16MHz, f_CPU = 16MHz + // Timer 4 (8 bit) used as system tick timer + // prescaler == 128 (2^7), Tfreq = 125kHz + // period = 1ms, so ARR = 125 + TIM4_PSCR = 7; + TIM4_ARR = 125; + // interrupts: update + TIM4_IER = TIM_IER_UIE; + // auto-reload + interrupt on overflow + enable + TIM4_CR1 = TIM_CR1_APRE | TIM_CR1_URS | TIM_CR1_CEN; +#ifdef UART + // Configure pins + // PC2 - PP output (on-board LED) + PORT(LED_PORT, DDR) |= LED_PIN; + PORT(LED_PORT, CR1) |= LED_PIN; + // PD5 - UART2_TX -- pseudo open-drain output; don't forget an pullup resistor! + PORT(UART_PORT, DDR) |= UART_TX_PIN; + PORT(UART_PORT, ODR) &= ~UART_TX_PIN; // turn off N push-down + //PORT(UART_PORT, CR1) |= UART_TX_PIN; +#endif + PC_DDR |= GPIO_PIN1; // setup timer's output + PC_ODR &= ~GPIO_PIN1; +#ifdef UART + // Configure UART + // 9 bit, no parity, 1 stop (UART_CR3 = 0 - reset value) + // 57600 on 16MHz: BRR1=0x11, BRR2=0x06 + UART2_BRR1 = 0x11; UART2_BRR2 = 0x06; + UART2_CR2 = UART_CR2_TEN | UART_CR2_REN | UART_CR2_RIEN; // Allow RX/TX, generate ints on rx +#endif + configure_timers(); + + // enable all interrupts + enableInterrupts(); + + // Loop + do{ + if(sample_flag){ // next sample in sound + I = Global_time - boom_start; // amount of us from start + if(I > boom_length || boom_start > Global_time){ + // end of sound + stop_snd(); + }else{ + I *= 16; + cur_vol = 16 - I / boom_length; // linear fading + // generate meander + if(bank_i){ + change_CCR(0); + bank_i = 0; + }else{ + change_CCR(cur_vol); + bank_i = 1; + } + } + } + if((Global_time - T > paused_val) || (T > Global_time)){ + T = Global_time; + #ifdef UART + PORT(LED_PORT, ODR) ^= LED_PIN; // blink on-board LED + #endif + } + #ifdef UART + if(UART_read_byte(&rb)){ // buffer isn't empty + switch(rb){ + case 'h': // help + case 'H': + uart_write("\nPROTO:\n" + "+/-\tLED period\n" + "P/p\tBoom\n" + "F\tSet frequency\n" + "L\tChange boom length (in ms)\n" + ); + break; + break; + case '+': + paused_val += 100; + if(paused_val > 10000) + paused_val = 500; // but not more than 10s + break; + case '-': + paused_val -= 100; + if(paused_val < 100) // but not less than 0.1s + paused_val = 500; + break; + case 'F': + if(readInt(&Ival) && Ival > 64){ + change_period(((U16)Ival) >> 4); // F*4 for 16 array values + }else error_msg("bad period"); + break; + case 'P': + case 'p': + play_snd(); + break; + case 'L': + if(readInt(&Ival) && Ival < 1000 && Ival > 1){ + boom_length = Ival; + }else error_msg("bad length"); + break; + } + } + #endif + }while(1); +} + + diff --git a/DRUM/main.h b/DRUM/main.h new file mode 100644 index 0000000..f202da6 --- /dev/null +++ b/DRUM/main.h @@ -0,0 +1,46 @@ +/* + * blinky.h + * + * Copyright 2014 Edward V. Emelianoff + * + * 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__ + +extern unsigned long Global_time, boom_start; // global time in ms +extern U8 sample_flag; // flag is set in interrupt -> next sample in sound +extern U8 snd_i, bank_i; + +#define UART_BUF_LEN 8 // max 7 bytes transmited in on operation +#define MIN_STEP_LENGTH 9 // max speed, microseconds for one microstep +#define THIS_DEVICE_NUM 1 // hardware number (0..255) can be changed by writting into EEPROM + +#ifdef UART +extern U8 UART_rx[]; +extern U8 UART_rx_start_i; +extern U8 UART_rx_cur_i; + +void UART_send_byte(U8 byte); +void uart_write(char *str); +void printUint(U8 *val, U8 len); +void error_msg(char *msg); +#endif + +#define check_UART_pointer(x) if(x == UART_BUF_LEN) x = 0; + +#endif // __MAIN_H__ diff --git a/DRUM/noicegen.c b/DRUM/noicegen.c new file mode 100644 index 0000000..29edc00 --- /dev/null +++ b/DRUM/noicegen.c @@ -0,0 +1,47 @@ +/* + * noicegen.c + * + * Copyright 2014 Edward V. Emelianoff + * + * 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 "noicegen.h" + +void configure_timers(){ + /**** TIMERS TIM1 - 1MHz, TIM2 - 1MHz ****/ + TIM1_PSCRH = 0; // this timer have 16 bit prescaler + TIM1_PSCRL = 3; // LSB should be written last as it updates prescaler + TIM2_PSCR = 4; + // Timer1 is PWM sound level generator + // Timer2 runs with F*16 to change voltage level (F - frequency of sound) + TIM1_ARRH = 0; + TIM1_ARRL = 16; + TIM1_CCR1H = 0; TIM1_CCR1L = 8; // default: 50% + // channel 1 generates PWM pulses + TIM1_CCMR1 = 0x60; // OC1M = 110b - PWM mode 1 ( 1 -> 0) + //TIM1_CCMR1 = 0x70; // OC1M = 111b - PWM mode 2 ( 0 -> 1) + TIM1_CCER1 = 1; // Channel 1 is on. Active is high + //TIM1_CCER1 = 3; // Channel 1 is on. Active is low + // default period: near 32ms + TIM2_ARRH = 127; TIM2_ARRL = 0; + // interrupts: update for timer 2, none for timer 1 + TIM1_IER = 0; + TIM2_IER = TIM_IER_UIE; + // enable PWM output for timer1 + TIM1_BKR |= 0x80; // MOE +} + diff --git a/DRUM/noicegen.h b/DRUM/noicegen.h new file mode 100644 index 0000000..36221be --- /dev/null +++ b/DRUM/noicegen.h @@ -0,0 +1,42 @@ +/* + * noicegen.h + * + * Copyright 2014 Edward V. Emelianoff + * + * 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 __NOICEGEN_H__ +#define __NOICEGEN_H__ + +#include "stm8l.h" +#include "main.h" + +#define TIM_EN (TIM_CR1_APRE | TIM_CR1_URS | TIM_CR1_CEN) + +void configure_timers(); + +// change period (in us) +#define change_period(F) do{TIM2_ARRH = F >> 8; TIM2_ARRL = F;}while(0) +#define change_CCR(C) do{TIM1_CCR1H = 0; TIM1_CCR1L = C;}while(0) +// change CCR value. U = Vcc * +#define play_snd() do{boom_start = Global_time; snd_i = 0; bank_i = 0; \ + TIM1_CR1 = TIM_EN; TIM2_CR1 = TIM_EN;}while(0) +#define stop_snd() do{TIM1_CR1 |= TIM_CR1_OPM; TIM2_CR1 = 0;}while(0) + + +#endif // __NOICEGEN_H__ diff --git a/DRUM/ports_definition.h b/DRUM/ports_definition.h new file mode 100644 index 0000000..90e5611 --- /dev/null +++ b/DRUM/ports_definition.h @@ -0,0 +1,43 @@ +/* + * ports_definition.h - definition of ports pins & so on + * + * 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 __PORTS_DEFINITION_H__ +#define __PORTS_DEFINITION_H__ + +#include "stm8l.h" + +// macro for using in port constructions like PORT(LED_PORT, ODR) = xx +#define CONCAT(a,b) a##_##b +#define PORT(a,b) CONCAT(a,b) + +// on-board LED +#define LED_PORT PC +#define LED_PIN GPIO_PIN2 + +// UART2_TX +#define UART_PORT PD +#define UART_TX_PIN GPIO_PIN5 + + + + +#endif // __PORTS_DEFINITION_H__ diff --git a/DRUM/waveforms.m b/DRUM/waveforms.m new file mode 100644 index 0000000..593c2d1 --- /dev/null +++ b/DRUM/waveforms.m @@ -0,0 +1,12 @@ +function waveforms(FN, nm) +% Prints on stdout 16 values for waveform bank +% FN - array with 16 values of Vout (Vmin..Vmax), will be normalized +% nm - name of array + MIN = min(FN); MAX = max(FN); + FN = (FN - MIN) / (MAX - MIN); + VAL = round(FN * 16); + printf("static const U8 %s[16] = {", nm) + for i = 1:15; printf("%d, ", VAL(i)); endfor; + printf("%d};\n", VAL(16)); + plot(VAL, 'o'); +endfunction diff --git a/distance_meter/Makefile b/distance_meter/Makefile new file mode 100644 index 0000000..b766c39 --- /dev/null +++ b/distance_meter/Makefile @@ -0,0 +1,34 @@ +NAME=testproj +SDCC=sdcc + +CCFLAGS=-DSTM8S105 -I../ -I/usr/share/sdcc/include -mstm8 --out-fmt-ihx +LDFLAGS= -mstm8 --out-fmt-ihx -lstm8 +FLASHFLAGS=-cstlinkv2 -pstm8s105 + +SRC=$(wildcard *.c) +# ATTENTION: FIRST in list should be file with main() +OBJ=$(SRC:%.c=%.rel) +TRASH=$(OBJ) $(SRC:%.c=%.rst) $(SRC:%.c=%.asm) $(SRC:%.c=%.lst) +TRASH+=$(SRC:%.c=%.sym) $(NAME).ihx $(NAME).lk $(NAME).map +INDEPENDENT_HEADERS=../stm8l.h ports_definition.h Makefile + +all: $(NAME).ihx + +$(SRC) : %.c : %.h $(INDEPENDENT_HEADERS) + @touch $@ + +%.h: ; + +clean: + rm -f $(TRASH) + +load: $(NAME).ihx + stm8flash $(FLASHFLAGS) -w $(NAME).ihx + +%.rel: %.c + $(SDCC) $(CCFLAGS) -c $< + +$(NAME).ihx: $(OBJ) + $(SDCC) $(LDFLAGS) $(OBJ) -o $(NAME).ihx + +.PHONY: all diff --git a/distance_meter/client-term/Makefile b/distance_meter/client-term/Makefile new file mode 100644 index 0000000..19bac1f --- /dev/null +++ b/distance_meter/client-term/Makefile @@ -0,0 +1,22 @@ +PROGRAM = client +LDFLAGS = +SRCS = client.c +CC = gcc +DEFINES = -D_XOPEN_SOURCE=501 +CXX = gcc +CFLAGS = -Wall -Werror $(DEFINES) +OBJS = $(SRCS:.c=.o) +all : $(PROGRAM) clean +$(PROGRAM) : $(OBJS) + $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) -o $(PROGRAM) + +# some addition dependencies +# %.o: %.c +# $(CC) $(LDFLAGS) $(CFLAGS) $< -o $@ +#$(SRCS) : %.c : %.h $(INDEPENDENT_HEADERS) +# @touch $@ + +clean: + /bin/rm -f *.o *~ +depend: + $(CXX) -MM $(CXX.SRCS) diff --git a/distance_meter/client-term/client.c b/distance_meter/client-term/client.c new file mode 100644 index 0000000..4cc16ff --- /dev/null +++ b/distance_meter/client-term/client.c @@ -0,0 +1,246 @@ +/* + * client.c - simple terminal client + * + * Copyright 2013 Edward V. Emelianoff + * + * 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 // tcsetattr +#include // tcsetattr, close, read, write +#include // ioctl +#include // printf, getchar, fopen, perror +#include // exit +#include // read +#include // read +#include // signal +#include // time +#include // memcpy +#include // int types +#include // gettimeofday + +#define CMSPAR 010000000000 + +double t0; // start time + +FILE *fout = NULL; // file for messages duplicating +char *comdev = "/dev/ttyUSB0"; +int BAUD_RATE = B57600; +struct termio oldtty, tty; // TTY flags +struct termios oldt, newt; // terminal flags +int comfd; // TTY fd + +/** + * function for different purposes that need to know time intervals + * @return double value: time in seconds + */ +double dtime(){ + double t; + struct timeval tv; + gettimeofday(&tv, NULL); + t = tv.tv_sec + ((double)tv.tv_usec)/1e6; + return t; +} + +/** + * Exit & return terminal to old state + * @param ex_stat - status (return code) + */ +void quit(int ex_stat){ + tcsetattr(STDIN_FILENO, TCSANOW, &oldt); // return terminal to previous state + ioctl(comfd, TCSANOW, &oldtty ); // return TTY to previous state + close(comfd); + if(fout) fclose(fout); + printf("Exit! (%d)\n", ex_stat); + exit(ex_stat); +} + +unsigned char crc(unsigned char data){ + unsigned char crc = data & 1; + unsigned int i; + for(i = 1; i<8; i++) crc ^= (data >> i) & 1; + return crc; +} + +/** + * Open & setup TTY, terminal + */ +void tty_init(){ + // terminal without echo + tcgetattr(STDIN_FILENO, &oldt); + newt = oldt; + newt.c_lflag &= ~(ICANON | ECHO); + if(tcsetattr(STDIN_FILENO, TCSANOW, &newt) < 0) quit(-2); + printf("\nOpen port...\n"); + if ((comfd = open(comdev,O_RDWR|O_NOCTTY|O_NONBLOCK)) < 0){ + fprintf(stderr,"Can't use port %s\n",comdev); + quit(1); + } + printf(" OK\nGet current settings...\n"); + if(ioctl(comfd,TCGETA,&oldtty) < 0) exit(-1); // Get settings + tty = oldtty; + tty.c_lflag = 0; // ~(ICANON | ECHO | ECHOE | ISIG) + tty.c_oflag = 0; + tty.c_iflag = 0; + tty.c_cflag = BAUD_RATE|CS8|CREAD|CLOCAL|PARENB; // we will emulate 9bit by PAR + tty.c_cc[VMIN] = 0; // non-canonical mode + tty.c_cc[VTIME] = 5; + if(ioctl(comfd,TCSETA,&tty) < 0) exit(-1); // set new mode + printf(" OK\n"); + tcsetattr(STDIN_FILENO, TCSANOW, &newt); +} + +/** + * Read character from console without echo + * @return char readed + */ +int read_console(){ + int rb; + struct timeval tv; + int retval; + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(STDIN_FILENO, &rfds); + tv.tv_sec = 0; tv.tv_usec = 10000; + retval = select(1, &rfds, NULL, NULL, &tv); + if(!retval) rb = 0; + else { + if(FD_ISSET(STDIN_FILENO, &rfds)) rb = getchar(); + else rb = 0; + } + return rb; +} + +/** + * getchar() without echo + * wait until at least one character pressed + * @return character readed + */ +int mygetchar(){ // getchar() without Enter + int ret; + do ret = read_console(); + while(ret == 0); + return ret; +} + +/** + * Read data from TTY + * @param buff (o) - buffer for data read + * @param length - buffer len + * @return amount of readed bytes + */ +size_t read_tty(uint8_t *buff, size_t length){ + ssize_t L = 0; + fd_set rfds; + struct timeval tv; + int retval; + FD_ZERO(&rfds); + FD_SET(comfd, &rfds); + tv.tv_sec = 0; tv.tv_usec = 10000; // wait for 10ms + retval = select(comfd + 1, &rfds, NULL, NULL, &tv); + if (!retval) return 0; + if(FD_ISSET(comfd, &rfds)){ + if((L = read(comfd, buff, length)) < 1) return 0; + } + return (size_t)L; +} + +void help(){ + printf("Use this commands:\n" + "H\tShow this help\n" + "q\tQuit\n" + ); +} + +#define dup_pr(...) do{printf(__VA_ARGS__); if(fout) fprintf(fout, __VA_ARGS__);}while(0) + +/** + * Set/reset nineth bit and send command + * @param + * @return + */ +void send_with_9(unsigned char cmd, int nineth){ + if(crc(cmd) ^ nineth) // (ODD CRC) XOR (set nineth) -> odd parity + tty.c_cflag |= PARODD; // odd parity + else + tty.c_cflag &= ~PARODD; // even parity + if(ioctl(comfd, TCSETA, &tty) < 0){ + perror("Ioctl"); + quit(2); + } + if(write(comfd, &cmd, 1) < 1){ + perror("Can't write to port"); + quit(2); + } +} + +void con_sig(int rb){ + if(rb < 1) return; + if(rb == 'q') quit(0); // q == exit + else if(rb == 'H'){ // this program help + help(); + return; + } + send_with_9((unsigned char)rb, 0); // just send command with zero nineth bit +} + +/** + * Get integer value from buffer + * @param buff (i) - buffer with int + * @param len - length of data in buffer (could be 2 or 4) + * @return + */ +uint32_t get_int(uint8_t *buff, size_t len){ + if(len != 2 && len != 4){ + fprintf(stdout, "Bad data length!\n"); + return 0xffffffff; + } + uint32_t data = 0; + uint8_t *i8 = (uint8_t*) &data; + if(len == 2) memcpy(i8, buff, 2); + else memcpy(i8, buff, 4); + return data; +} + +int main(int argc, char *argv[]){ + int rb; + uint8_t buff[128]; + size_t L; + if(argc == 2){ + fout = fopen(argv[1], "a"); + if(!fout){ + perror("Can't open output file"); + exit(-1); + } + setbuf(fout, NULL); + } + tty_init(); + signal(SIGTERM, quit); // kill (-15) + signal(SIGINT, quit); // ctrl+C + signal(SIGQUIT, SIG_IGN); // ctrl+\ . + signal(SIGTSTP, SIG_IGN); // ctrl+Z + setbuf(stdout, NULL); + t0 = dtime(); + while(1){ + rb = read_console(); + if(rb > 0) con_sig(rb); + L = read_tty(buff, 127); + if(L){ + buff[L] = 0; + printf("%s", buff); + if(fout) fprintf(fout, "%zd\t%s\n", time(NULL), buff); + } + } +} diff --git a/distance_meter/interrupts.c b/distance_meter/interrupts.c new file mode 100644 index 0000000..d016a07 --- /dev/null +++ b/distance_meter/interrupts.c @@ -0,0 +1,205 @@ +/* + * interrupts.c + * + * Copyright 2014 Edward V. Emelianoff + * + * 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 "ports_definition.h" +#include "main.h" + +// Top Level Interrupt +INTERRUPT_HANDLER(TLI_IRQHandler, 0){} + +// Auto Wake Up Interrupt +INTERRUPT_HANDLER(AWU_IRQHandler, 1){} + +// Clock Controller Interrupt +INTERRUPT_HANDLER(CLK_IRQHandler, 2){} + +// External Interrupt PORTA +INTERRUPT_HANDLER(EXTI_PORTA_IRQHandler, 3){} + +// External Interrupt PORTB +INTERRUPT_HANDLER(EXTI_PORTB_IRQHandler, 4){} + +// External Interrupt PORTC +INTERRUPT_HANDLER(EXTI_PORTC_IRQHandler, 5){} + +// External Interrupt PORTD +INTERRUPT_HANDLER(EXTI_PORTD_IRQHandler, 6){} + +// External Interrupt PORTE +INTERRUPT_HANDLER(EXTI_PORTE_IRQHandler, 7){} + +#ifdef STM8S903 +// External Interrupt PORTF +INTERRUPT_HANDLER(EXTI_PORTF_IRQHandler, 8){} +#endif // STM8S903 + +#if defined (STM8S208) || defined (STM8AF52Ax) +// CAN RX Interrupt routine. +INTERRUPT_HANDLER(CAN_RX_IRQHandler, 8){} + +// CAN TX Interrupt routine. +INTERRUPT_HANDLER(CAN_TX_IRQHandler, 9){} +#endif // STM8S208 || STM8AF52Ax + +// SPI Interrupt routine. +INTERRUPT_HANDLER(SPI_IRQHandler, 10){} + +volatile U8 in_measure; // flag of measurenent +// Timer1 Update/Overflow/Trigger/Break Interrupt +// in_measure == 1 means that we will get wrong result as pulse length is too long +// pulse of 65536us is 32768us to something == near 11 meters +INTERRUPT_HANDLER(TIM1_UPD_OVF_TRG_BRK_IRQHandler, 11){ + TIM1_SR1 &= ~TIM_SR1_UIF; // clear this flag + if(!in_measure) return; // not process when there's nothing started + //uart_write("OVF\n"); + US_flag = 3; + TIM1_SR1 = 0; + TIM1_SR2 = 0; + TIM1_CR1 = 0;TIM1_CCER1 &= ~0x11; // stop timer + in_measure = 0; +} + +// Timer1 Capture/Compare Interrupt routine. +// pulse width measurement: PC1 - TIM1_CH1 +INTERRUPT_HANDLER(TIM1_CAP_COM_IRQHandler, 12){ + /*U16 P = TIM1_CNTRH; + P |= TIM1_CNTRL << 8; + printUint((U8*)&P,2); + printUint(&TIM1_CCR2H,1); + printUint(&TIM1_CCR2L,1); + printUint(&TIM1_CCR1H,1); + printUint(&TIM1_CCR1L,1); + printUint(&TIM1_CNTRH,1); + printUint(&TIM1_CNTRL,1);*/ + //Pulse_length = ((U16)TIM1_CCR2H << 8) | TIM1_CCR2L; + if(TIM1_SR1 & TIM_SR1_CC2IF){ + TIM1_SR1 = 0; // clear all interrupt flags + TIM1_CR1 = 0;TIM1_CCER1 &= ~0x11; // stop timer + in_measure = 0; // work done + // uart_write("CCR2\n"); + if(TIM1_SR2){ // overcapture: noice etc. + TIM1_SR2 = 0; + US_flag = 1; + }else{ + US_flag = 2; + } + } + if(TIM1_SR1 & TIM_SR1_CC1IF){ + TIM1_SR1 &= ~TIM_SR1_CC1IF; // clear this interrupt flags + in_measure = 1; // start of measurement + // uart_write("CCR1\n"); + /* TIM1_CNTRH = 0; TIM1_CNTRL = 0; + TIM1_CCR2H = 0; TIM1_CCR2L = 0; + TIM1_CCR1H = 0; TIM1_CCR1L = 0;*/ + } +} + +#ifdef STM8S903 +// Timer5 Update/Overflow/Break/Trigger Interrupt +INTERRUPT_HANDLER(TIM5_UPD_OVF_BRK_TRG_IRQHandler, 13){} + +// Timer5 Capture/Compare Interrupt +INTERRUPT_HANDLER(TIM5_CAP_COM_IRQHandler, 14){} + +#else // STM8S208, STM8S207, STM8S105 or STM8S103 or STM8AF62Ax or STM8AF52Ax or STM8AF626x +// Timer2 Update/Overflow/Break Interrupt +INTERRUPT_HANDLER(TIM2_UPD_OVF_BRK_IRQHandler, 13){} + +// Timer2 Capture/Compare Interrupt +INTERRUPT_HANDLER(TIM2_CAP_COM_IRQHandler, 14){} +#endif // STM8S903 + +#if defined (STM8S208) || defined(STM8S207) || defined(STM8S007) || defined(STM8S105) || \ + defined(STM8S005) || defined (STM8AF62Ax) || defined (STM8AF52Ax) || defined (STM8AF626x) +// Timer3 Update/Overflow/Break Interrupt +INTERRUPT_HANDLER(TIM3_UPD_OVF_BRK_IRQHandler, 15){} + +// Timer3 Capture/Compare Interrupt +INTERRUPT_HANDLER(TIM3_CAP_COM_IRQHandler, 16){} +#endif // STM8S208, STM8S207 or STM8S105 or STM8AF62Ax or STM8AF52Ax or STM8AF626x + +#if defined (STM8S208) || defined(STM8S207) || defined(STM8S007) || defined(STM8S103) || \ + defined(STM8S003) || defined (STM8AF62Ax) || defined (STM8AF52Ax) || defined (STM8S903) +// UART1 TX Interrupt +INTERRUPT_HANDLER(UART1_TX_IRQHandler, 17){} + +// UART1 RX Interrupt +INTERRUPT_HANDLER(UART1_RX_IRQHandler, 18){} +#endif // STM8S208 or STM8S207 or STM8S103 or STM8S903 or STM8AF62Ax or STM8AF52Ax + +// I2C Interrupt +INTERRUPT_HANDLER(I2C_IRQHandler, 19){} + +#if defined(STM8S105) || defined(STM8S005) || defined (STM8AF626x) +// UART2 TX interrupt +INTERRUPT_HANDLER(UART2_TX_IRQHandler, 20){} + +// UART2 RX interrupt +INTERRUPT_HANDLER(UART2_RX_IRQHandler, 21){ + U8 rb; + if(UART2_SR & UART_SR_RXNE){ // data received + rb = UART2_DR; // read received byte & clear RXNE flag + UART_send_byte(rb); // echo received symbol + UART_rx[UART_rx_cur_i++] = rb; // put received byte into cycled buffer + if(UART_rx_cur_i == UART_rx_start_i){ // Oops: buffer overflow! Just forget old data + UART_rx_start_i++; + check_UART_pointer(UART_rx_start_i); + } + check_UART_pointer(UART_rx_cur_i); + } +} +#endif // STM8S105 or STM8AF626x + +#if defined(STM8S207) || defined(STM8S007) || defined(STM8S208) || defined (STM8AF52Ax) || defined (STM8AF62Ax) +// UART3 TX interrupt +INTERRUPT_HANDLER(UART3_TX_IRQHandler, 20){} + +// UART3 RX interrupt +INTERRUPT_HANDLER(UART3_RX_IRQHandler, 21){} +#endif // STM8S208 or STM8S207 or STM8AF52Ax or STM8AF62Ax + +#if defined(STM8S207) || defined(STM8S007) || defined(STM8S208) || defined (STM8AF52Ax) || defined (STM8AF62Ax) +// ADC2 interrupt +INTERRUPT_HANDLER(ADC2_IRQHandler, 22){} +#else +// ADC1 interrupt +INTERRUPT_HANDLER(ADC1_IRQHandler, 22){ + ADC_value = ADC_DRL; // in right-alignment mode we should first read LSB + ADC_value |= ADC_DRH << 8; + ADC_CSR &= 0x3f; // clear EOC & AWD flags +} +#endif // STM8S208 or STM8S207 or STM8AF52Ax or STM8AF62Ax + +#ifdef STM8S903 +// Timer6 Update/Overflow/Trigger Interrupt +INTERRUPT_HANDLER(TIM6_UPD_OVF_TRG_IRQHandler, 23){} +#else // STM8S208, STM8S207, STM8S105 or STM8S103 or STM8AF52Ax or STM8AF62Ax or STM8AF626x +// Timer4 Update/Overflow Interrupt +INTERRUPT_HANDLER(TIM4_UPD_OVF_IRQHandler, 23){ + if(TIM4_SR & TIM_SR1_UIF){ // update interrupt + Global_time++; // increase timer + } + TIM4_SR = 0; // clear all interrupt flags +} +#endif // STM8S903 + +// Eeprom EEC Interrupt +INTERRUPT_HANDLER(EEPROM_EEC_IRQHandler, 24){} diff --git a/distance_meter/interrupts.h b/distance_meter/interrupts.h new file mode 100644 index 0000000..6edf384 --- /dev/null +++ b/distance_meter/interrupts.h @@ -0,0 +1,144 @@ +/* + * interrupts.h + * + * Copyright 2014 Edward V. Emelianoff + * + * 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 __INTERRUPTS_H__ +#define __INTERRUPTS_H__ + +#include "stm8l.h" + +// Top Level Interrupt +INTERRUPT_DEFINITION(TLI_IRQHandler, 0); + +// Auto Wake Up Interrupt +INTERRUPT_DEFINITION(AWU_IRQHandler, 1); + +// Clock Controller Interrupt +INTERRUPT_DEFINITION(CLK_IRQHandler, 2); + +// External Interrupt PORTA +INTERRUPT_DEFINITION(EXTI_PORTA_IRQHandler, 3); + +// External Interrupt PORTB +INTERRUPT_DEFINITION(EXTI_PORTB_IRQHandler, 4); + +// External Interrupt PORTC +INTERRUPT_DEFINITION(EXTI_PORTC_IRQHandler, 5); + +// External Interrupt PORTD +INTERRUPT_DEFINITION(EXTI_PORTD_IRQHandler, 6); + +// External Interrupt PORTE +INTERRUPT_DEFINITION(EXTI_PORTE_IRQHandler, 7); + +#ifdef STM8S903 +// External Interrupt PORTF +INTERRUPT_DEFINITION(EXTI_PORTF_IRQHandler, 8); +#endif // STM8S903 + +#if defined (STM8S208) || defined (STM8AF52Ax) +// CAN RX Interrupt routine. +INTERRUPT_DEFINITION(CAN_RX_IRQHandler, 8); + +// CAN TX Interrupt routine. +INTERRUPT_DEFINITION(CAN_TX_IRQHandler, 9); +#endif // STM8S208 || STM8AF52Ax + +// SPI Interrupt routine. +INTERRUPT_DEFINITION(SPI_IRQHandler, 10); + +// Timer1 Update/Overflow/Trigger/Break Interrupt +INTERRUPT_DEFINITION(TIM1_UPD_OVF_TRG_BRK_IRQHandler, 11); + +// Timer1 Capture/Compare Interrupt routine. +INTERRUPT_DEFINITION(TIM1_CAP_COM_IRQHandler, 12); + +#ifdef STM8S903 +// Timer5 Update/Overflow/Break/Trigger Interrupt +INTERRUPT_DEFINITION(TIM5_UPD_OVF_BRK_TRG_IRQHandler, 13); + +// Timer5 Capture/Compare Interrupt +INTERRUPT_DEFINITION(TIM5_CAP_COM_IRQHandler, 14); + +#else // STM8S208, STM8S207, STM8S105 or STM8S103 or STM8AF62Ax or STM8AF52Ax or STM8AF626x +// Timer2 Update/Overflow/Break Interrupt +INTERRUPT_DEFINITION(TIM2_UPD_OVF_BRK_IRQHandler, 13); + +// Timer2 Capture/Compare Interrupt +INTERRUPT_DEFINITION(TIM2_CAP_COM_IRQHandler, 14); +#endif // STM8S903 + +#if defined (STM8S208) || defined(STM8S207) || defined(STM8S007) || defined(STM8S105) || \ + defined(STM8S005) || defined (STM8AF62Ax) || defined (STM8AF52Ax) || defined (STM8AF626x) +// Timer3 Update/Overflow/Break Interrupt +INTERRUPT_DEFINITION(TIM3_UPD_OVF_BRK_IRQHandler, 15); + +// Timer3 Capture/Compare Interrupt +INTERRUPT_DEFINITION(TIM3_CAP_COM_IRQHandler, 16); +#endif // STM8S208, STM8S207 or STM8S105 or STM8AF62Ax or STM8AF52Ax or STM8AF626x + +#if defined (STM8S208) || defined(STM8S207) || defined(STM8S007) || defined(STM8S103) || \ + defined(STM8S003) || defined (STM8AF62Ax) || defined (STM8AF52Ax) || defined (STM8S903) +// UART1 TX Interrupt +INTERRUPT_DEFINITION(UART1_TX_IRQHandler, 17); + +// UART1 RX Interrupt +INTERRUPT_DEFINITION(UART1_RX_IRQHandler, 18); +#endif // STM8S208 or STM8S207 or STM8S103 or STM8S903 or STM8AF62Ax or STM8AF52Ax + +// I2C Interrupt +INTERRUPT_DEFINITION(I2C_IRQHandler, 19); + +#if defined(STM8S105) || defined(STM8S005) || defined (STM8AF626x) +// UART2 TX interrupt +INTERRUPT_DEFINITION(UART2_TX_IRQHandler, 20); + +// UART2 RX interrupt +INTERRUPT_DEFINITION(UART2_RX_IRQHandler, 21); +#endif // STM8S105 or STM8AF626x + +#if defined(STM8S207) || defined(STM8S007) || defined(STM8S208) || defined (STM8AF52Ax) || defined (STM8AF62Ax) +// UART3 TX interrupt +INTERRUPT_DEFINITION(UART3_TX_IRQHandler, 20); + +// UART3 RX interrupt +INTERRUPT_DEFINITION(UART3_RX_IRQHandler, 21); +#endif // STM8S208 or STM8S207 or STM8AF52Ax or STM8AF62Ax + +#if defined(STM8S207) || defined(STM8S007) || defined(STM8S208) || defined (STM8AF52Ax) || defined (STM8AF62Ax) +// ADC2 interrupt +INTERRUPT_DEFINITION(ADC2_IRQHandler, 22); +#else // STM8S105, STM8S103 or STM8S903 or STM8AF626x +// ADC1 interrupt +INTERRUPT_DEFINITION(ADC1_IRQHandler, 22); +#endif // STM8S208 or STM8S207 or STM8AF52Ax or STM8AF62Ax + +#ifdef STM8S903 +// Timer6 Update/Overflow/Trigger Interrupt +INTERRUPT_DEFINITION(TIM6_UPD_OVF_TRG_IRQHandler, 23); +#else // STM8S208, STM8S207, STM8S105 or STM8S103 or STM8AF52Ax or STM8AF62Ax or STM8AF626x +// Timer4 Update/Overflow Interrupt +INTERRUPT_DEFINITION(TIM4_UPD_OVF_IRQHandler, 23); +#endif // STM8S903 + +// Eeprom EEC Interrupt +INTERRUPT_DEFINITION(EEPROM_EEC_IRQHandler, 24); + +#endif // __INTERRUPTS_H__ diff --git a/distance_meter/main.c b/distance_meter/main.c new file mode 100644 index 0000000..4afd22e --- /dev/null +++ b/distance_meter/main.c @@ -0,0 +1,389 @@ +/* + * main.c + * + * Copyright 2014 Edward V. Emelianoff + * + * 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 "stm8l.h" +#include "ports_definition.h" +#include "interrupts.h" +#include "main.h" + +/* + * 0 0000 + * 1 0001 + * 2 0010 + * 3 0011 + * 4 0100 + * 5 0101 + * 6 0110 + * 7 0111 + * 8 1000 + * 9 1001 + * a 1010 + * b 1011 + * c 1100 + * d 1101 + * e 1110 + * f 1111 + */ + +unsigned long Global_time = 0L; // global time in ms +U16 paused_val = 500; // interval between LED flashing + +volatile U16 ADC_value = 0; // value of last ADC measurement + +volatile U16 Pulse_length = 11; // length of ultrasonic echo pulse +U8 US_flag = 0;// 0 - conversion in progress; 1 - conversion error; 2 - conversion done; 3 - overflow + +U8 UART_rx[UART_BUF_LEN]; // cycle buffer for received data +U8 UART_rx_start_i = 0; // started index of received data (from which reading starts) +U8 UART_rx_cur_i = 0; // index of current first byte in rx array (to which data will be written) +// ATTENTION! to change global variable in PROGRAM memory, it should be CONST!!! +//const U8 UART_devNUM = THIS_DEVICE_NUM; // device number, master sais it + +/** + * Send one byte through UART + * @param byte - data to send + */ +void UART_send_byte(U8 byte){ + UART2_DR = byte; + while(!(UART2_SR & UART_SR_TC)); +} + +void uart_write(char *str){ + while(*str){ + UART2_DR = *str++; + while(!(UART2_SR & UART_SR_TC)); + } +} + +/** + * Read one byte from Rx buffer + * @param byte - where to store readed data + * @return 1 in case of non-empty buffer + */ +U8 UART_read_byte(U8 *byte){ + if(UART_rx_start_i == UART_rx_cur_i) // buffer is empty + return 0; + *byte = UART_rx[UART_rx_start_i++]; + check_UART_pointer(UART_rx_start_i); + return 1; +} + +void printUint(U8 *val, U8 len){ + unsigned long Number = 0; + U8 i = len; + char ch; + U8 decimal_buff[12]; // max len of U32 == 10 + \n + \0 + if(len > 4 || len == 3 || len == 0) return; + for(i = 0; i < 12; i++) + decimal_buff[i] = 0; + decimal_buff[10] = '\n'; + ch = 9; + switch(len){ + case 1: + Number = *((U8*)val); + break; + case 2: + Number = *((U16*)val); + break; + case 4: + Number = *((unsigned long*)val); + break; + } + do{ + i = Number % 10L; + decimal_buff[ch--] = i + '0'; + Number /= 10L; + }while(Number && ch > -1); + uart_write((char*)&decimal_buff[ch+1]); +} +/* +U8 U8toHEX(U8 val){ + val &= 0x0f; + if(val < 10) val += '0'; + else val += 'a' - 10; + return val; +} + +void printUintHEX(U8 *val, U8 len){ + U8 i, V; + uart_write("0x"); + for(i = 0; i < len; i++){ + V = *val++; + UART_send_byte(U8toHEX(V>>4)); // MSB + UART_send_byte(U8toHEX(V)); // LSB + } + UART_send_byte('\n'); +}*/ + +U8 readInt(int *val){ + unsigned long T = Global_time; + unsigned long R = 0; + int readed; + U8 sign = 0, rb, ret = 0, bad = 0; + do{ + if(!UART_read_byte(&rb)) continue; + if(rb == '-' && R == 0){ // negative number + sign = 1; + continue; + } + if(rb < '0' || rb > '9') break; // number ends with any non-digit symbol that will be omitted + ret = 1; // there's at least one digit + R = R * 10L + rb - '0'; + if(R > 0x7fff){ // bad value + R = 0; + bad = 0; + } + }while(Global_time - T < 10000); // wait no longer than 10s + if(bad || !ret) return 0; + readed = (int) R; + if(sign) readed *= -1; + *val = readed; + return 1; +} + +void error_msg(char *msg){ + uart_write("\nERROR: "); + uart_write(msg); + UART_send_byte('\n'); +} + +/** + * Change variable stored in program memory + * !!! You can change only const values (non-constants are initializes on program start) + * @param addr - variable address + * @param new value + * @return 0 in case of error + */ +U8 change_progmem_value(U8 *addr, U8 val){ + // unlock memory + FLASH_PUKR = EEPROM_KEY2; + FLASH_PUKR = EEPROM_KEY1; + // check bit PUL=1 in FLASH_IAPSR + if(!FLASH_IAPSR & 0x02) + return 0; + *addr = val; + // clear PUL to lock write + FLASH_IAPSR &= ~0x02; + return 1; +} + +/* +U8 change_eeprom_value(U8 *addr, U8 val){ + // unlock memory + FLASH_DUKR = EEPROM_KEY1; + FLASH_DUKR = EEPROM_KEY2; + // check bit DUL=1 in FLASH_IAPSR + if(!FLASH_IAPSR & 0x08) + return 0; + *addr = val; + // clear DUL to lock write + FLASH_IAPSR &= ~0x08; + return 1; +} +*/ + +/** + * Start measurements by ultrasonic distance meter + * @param + * @return + */ +void US_start(){ + U8 i; + TIM1_CNTRH = 0; TIM1_CNTRL = 0; + TIM1_CCR2H = 0; TIM1_CCR2L = 0; + US_flag = 0; + // post initial pulse + PORT(US_OUT_PORT, ODR) |= US_OUT_PIN; + for(i = 0; i < 160; i++) nop(); // wait at least for 10us + PORT(US_OUT_PORT, ODR) &= ~US_OUT_PIN; + // Enable the captures by writing the CC1E and CC2E bits to 1 in the TIM1_CCER1 register. + TIM1_CCER1 |= 0x11; + TIM1_CR1 = TIM_CR1_CEN; // turn on timer +} + +/** + * Check ultrasonic flag value and send message + * @param + * @return + */ +void US_check(){ + unsigned long L; + if(!US_flag) return; + if(US_flag == 1){ // error - write message + error_msg("measurement overcapture"); + }else if(US_flag == 3){ // overflow + error_msg("TIM1 overflow"); + }else{ // all OK - write measured length + Pulse_length = ((U16)TIM1_CCR2H << 8) | TIM1_CCR2L; + printUint((U8*)&Pulse_length,2); + // sound velocity == 340m/s in normal conditions + // So distance = pulse * 1e-6(us) * 340 / 2 + // in millimeters this is equal of pulse*170/1000 + L = ((unsigned long) Pulse_length) * 170L; + L /= 1000L; + uart_write("Distance (mm): "); + printUint((U8*)&L, 4); + } + US_flag = 0; +} + +int main(){ + unsigned long T = 0L; + //int Ival; +// unsigned long ul; +// U16 u16; + U8 rb; + + CFG_GCR |= 1; // disable SWIM + + // Configure clocking + CLK_CKDIVR = 0; // F_HSI = 16MHz, f_CPU = 16MHz + + // Timer 4 (8 bit) used as system tick timer + // prescaler == 128 (2^7), Tfreq = 125kHz + // period = 1ms, so ARR = 125 + TIM4_PSCR = 7; + TIM4_ARR = 125; + // interrupts: update + TIM4_IER = TIM_IER_UIE; + // auto-reload + interrupt on overflow + enable + TIM4_CR1 = TIM_CR1_APRE | TIM_CR1_URS | TIM_CR1_CEN; + + // Configure Timer1 for measurement of US pulse width: + // main frequency: 1MHz + // prescaler = f_{in}/f_{tim1} - 1 + // set Timer1 to 1MHz: 16/1 - 1 = 15 + TIM1_PSCRH = 0; + TIM1_PSCRL = 15; // LSB should be written last as it updates prescaler + // capture/compare channel + // channel CC1 (0->1) stores low pulse length, + // channel CC2 (1->0) stores time period between two consequent zero-transitions + TIM1_IER = TIM_IER_CC2IE | TIM_IER_CC1IE | TIM_IER_UIE;// enable interrupt on CC2 & overflow + // 1. Select the active input capture or trigger input for TIM1_CCR1 by writing the CC1S bits + // to 01 in the TIM1_CCMR1 register (TI1FP1 selected). + // IC1F = 0 - no filter + // IC1PSC = 0 - no prescaler + // TIM1_CCMR1: IC1F[3:0] | IC1PSC[1:0] | CC1S[1:0] + TIM1_CCMR1 = 1; + // 3. Select the active input for TIM1_CCR2 by writing the CC2S bits to 10 in the + // TIM1_CCMR2 register (TI1FP2 selected). + TIM1_CCMR2 = 2; + // 2. Select the active polarity for TI1FP1 (used for both capture and counter clear in + // TIMx_CCR1) by writing the CC1P bit to 0 (TI1FP1 active on rising edge). + // 4. Select the active polarity for TI1FP2 (used for capture in TIM1_CCR2) by writing the + // CC2P bit to 1 (TI1FP2 active on falling edge). + // TIM1_CCER1: CC2NP | CC2NE | CC2P | CC2E | CC1NP | CC1NE | CC1P | CC1E + TIM1_CCER1 = 0x20; + // 5. Select the valid trigger input by writing the TS bits to 101 in the + // TIM1_SMCR register (TI1FP1 selected). + // 6. Configure the clock/trigger controller in reset mode by writing the + // SMS bits to 100 in the TIM1_SMCR register + // TIM1_SMCR: MSM | TS[2:0] | (reserved) | SMS[2:0] + TIM1_SMCR = 0x54; + + + //TIM1_CR1 = 0; + + + + // Configure ADC + // select PD2[AIN3] & enable interrupt for EOC + ADC_CSR = 0x23; + ADC_TDRL = 0x08; // disable Schmitt triger for AIN3 + // right alignment + ADC_CR2 = 0x08; // don't forget: first read ADC_DRL! + // f_{ADC} = f/18 & continuous non-buffered conversion & wake it up + ADC_CR1 = 0x73; + ADC_CR1 = 0x73; // turn on ADC (this needs second write operation) + + // Configure pins + // PC2 - PP output (on-board LED) + PORT(LED_PORT, DDR) |= LED_PIN; + PORT(LED_PORT, CR1) |= LED_PIN; + // PD5 - UART2_TX -- pseudo open-drain output; don't forget an pullup resistor! + PORT(UART_PORT, DDR) |= UART_TX_PIN; + PORT(UART_PORT, ODR) &= ~UART_TX_PIN; // turn off N push-down + //PORT(UART_PORT, CR1) |= UART_TX_PIN; + // Ultrasonic + // out, PP + PORT(US_OUT_PORT, DDR) |= US_OUT_PIN; + PORT(US_OUT_PORT, CR1) |= US_OUT_PIN; + // + + // Configure UART + // 9 bit, no parity, 1 stop (UART_CR3 = 0 - reset value) + // 57600 on 16MHz: BRR1=0x11, BRR2=0x06 + UART2_BRR1 = 0x11; UART2_BRR2 = 0x06; + UART2_CR1 = UART_CR1_M; // M = 1 -- 9bits + UART2_CR2 = UART_CR2_TEN | UART_CR2_REN | UART_CR2_RIEN; // Allow RX, generate ints on rx + + // enable all interrupts + enableInterrupts(); + // Loop + do{ + if((Global_time - T > paused_val) || (T > Global_time)){ + T = Global_time; + PORT(LED_PORT, ODR) ^= LED_PIN; // blink on-board LED + } + if(US_flag) US_check(); // end of measurement with ultrasonic? + if(UART_read_byte(&rb)){ // buffer isn't empty + switch(rb){ + case 'h': // help + case 'H': + uart_write("\nPROTO:\n" + "+/-\tLED period\n" + "A\tprint ADC value\n" + "D\tmeasure distance by US\n" + ); + break; + case '+': + paused_val += 100; + if(paused_val > 10000) + paused_val = 500; // but not more than 10s + break; + case '-': + paused_val -= 100; + if(paused_val < 100) // but not less than 0.1s + paused_val = 500; + break; + case 'A': +// ul = ADC_value * 3300L; +// u16 = (U16)(ul >> 10); // 0..3300 - U in mv +// printUint((U8*)&u16,2); + printUint((U8*)&ADC_value,2); + break; + case 'D': + US_start(); + break; +/* case 'N': + if(readInt(&Ival) && Ival > 0 && Ival < 256) + if(!change_progmem_value(&UART_devNUM, (unsigned int) Ival)) + error_msg("can't change val"); + break; +*/ + default: + break; + } + } + }while(1); +} + + diff --git a/distance_meter/main.h b/distance_meter/main.h new file mode 100644 index 0000000..2341bc1 --- /dev/null +++ b/distance_meter/main.h @@ -0,0 +1,47 @@ +/* + * main.h + * + * Copyright 2014 Edward V. Emelianoff + * + * 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__ + +extern unsigned long Global_time; // global time in ms + +#define UART_BUF_LEN 8 // max 7 bytes transmited in on operation + +extern U8 UART_rx[]; +extern U8 UART_rx_start_i; +extern U8 UART_rx_cur_i; + +extern U8 US_flag; + +extern volatile U16 ADC_value ; +extern volatile U16 Pulse_length; + +//extern const U8 UART_devNUM; + +void UART_send_byte(U8 byte); +void uart_write(char *str); +void printUint(U8 *val, U8 len); +void error_msg(char *msg); + +#define check_UART_pointer(x) if(x == UART_BUF_LEN) x = 0; + +#endif // __MAIN_H__ diff --git a/distance_meter/ports_definition.h b/distance_meter/ports_definition.h new file mode 100644 index 0000000..602afd7 --- /dev/null +++ b/distance_meter/ports_definition.h @@ -0,0 +1,48 @@ +/* + * ports_definition.h - definition of ports pins & so on + * + * 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 __PORTS_DEFINITION_H__ +#define __PORTS_DEFINITION_H__ + +#include "stm8l.h" + +// macro for using in port constructions like PORT(LED_PORT, ODR) = xx +#define CONCAT(a,b) a##_##b +#define PORT(a,b) CONCAT(a,b) + +// on-board LED +#define LED_PORT PC +#define LED_PIN GPIO_PIN2 + +// UART2_TX +#define UART_PORT PD +#define UART_TX_PIN GPIO_PIN5 + +// Ultrasonic interface +// out: PE5 +#define US_OUT_PORT PE +#define US_OUT_PIN GPIO_PIN5 +// pulse width measurement: PC1 - TIM1_CH1 +#define US_IN_PORT PC +#define US_IN_PIN GPIO_PIN1 + +#endif // __PORTS_DEFINITION_H__