diff --git a/with_opencm3/AD7794.c b/with_opencm3/AD7794.c index cf2a4c2..4843523 100644 --- a/with_opencm3/AD7794.c +++ b/with_opencm3/AD7794.c @@ -20,6 +20,7 @@ */ #include "main.h" +#include "AD7794.h" #include "spi.h" #include "cdcacm.h" diff --git a/with_opencm3/Makefile b/with_opencm3/Makefile index 8e487d8..1a12f72 100644 --- a/with_opencm3/Makefile +++ b/with_opencm3/Makefile @@ -5,7 +5,8 @@ BOOTSPEED ?= 115200 # for example, if you have STM32F103VBT6, you should write: LDSCRIPT = ld/stm32f103xB.ld LIBNAME = opencm3_stm32f1 -DEFS = -DSTM32F1 -DEBUG +DEFS = -DSTM32F1 +# -DEBUG OBJDIR = mk INDEPENDENT_HEADERS= diff --git a/with_opencm3/README b/with_opencm3/README index 783cfce..b88b6e8 100644 --- a/with_opencm3/README +++ b/with_opencm3/README @@ -1,4 +1,4 @@ -The work begins +The work started First PCB have been prodused, so I need "only" to solder elements & finish the code Pinout of MCU is in file schematics/STM32_PINS diff --git a/with_opencm3/cdcacm.c b/with_opencm3/cdcacm.c index f244bc9..f59d1cc 100644 --- a/with_opencm3/cdcacm.c +++ b/with_opencm3/cdcacm.c @@ -22,6 +22,7 @@ #include "user_proto.h" #include "main.h" #include "uart.h" +#include "sync.h" // Buffer for USB Tx static uint8_t USB_Tx_Buffer[USB_TX_DATA_SIZE]; diff --git a/with_opencm3/flash.c b/with_opencm3/flash.c index 4d080e4..8707058 100644 --- a/with_opencm3/flash.c +++ b/with_opencm3/flash.c @@ -37,7 +37,18 @@ const flash_data Flash_Data __attribute__ ((aligned(FLASH_BLOCK_SIZE))) = { ._ADC_divisors = {1,1,1,1,1,1,1,1, // TRD 25, // shutter 7 // power - } + }, + ._OW_id_array = { // ID of 1-wire sensors + {0x10, 0xad, 0xbc, 0x8f, 0x02, 0x08, 0x00, 0xf9}, + {0x10, 0x78, 0xe4, 0x8f, 0x02, 0x08, 0x00, 0x7d}, + {0x10, 0x46, 0x0a, 0x90, 0x02, 0x08, 0x00, 0x59}, + {0x10, 0x68, 0xd6, 0x8f, 0x02, 0x08, 0x00, 0x21}, + {0x10, 0x7c, 0xee, 0x8f, 0x02, 0x08, 0x00, 0x1c}, + {0x10, 0xf7, 0x02, 0x90, 0x02, 0x08, 0x00, 0x57}, + {0x10, 0x92, 0xf1, 0x8f, 0x02, 0x08, 0x00, 0x35}, + {0x10, 0x5f, 0x02, 0x90, 0x02, 0x08, 0x00, 0xaa} + }, + ._OW_dev_amount = 8 } }; @@ -104,14 +115,27 @@ void dump_flash_data(sendfun s){ // P("magick: ", s); // print_int(Stored_Data.magick, s); P("\nADC multipliers: ", s); - for(i = 0; i < ADC_CHANNELS_NUMBER; i++){ + for(i = 0; i < ADC_CHANNELS_NUMBER; ++i){ if(i) P(", ", s); print_int(Flash_Data.all_stored._ADC_multipliers[i], s); } P("\nADC divisors: ", s); - for(i = 0; i < ADC_CHANNELS_NUMBER; i++){ + for(i = 0; i < ADC_CHANNELS_NUMBER; ++i){ if(i) P(", ", s); print_int(Flash_Data.all_stored._ADC_divisors[i], s); } - s('\n'); + P("\n1-wire IDs:\n", s); + for(i = 0; i < OW_dev_amount; ++i){ + int j; + uint8_t *ROM = OW_id_array[i]; + s('\t'); + print_int(i, s); + P(") ", s); + for(j = 0; j < 8; ++j){ + if(j) P(", ", s); + print_hex(&ROM[j], 1, s); + } + s('\n'); + } } + diff --git a/with_opencm3/flash.h b/with_opencm3/flash.h index f10677a..f1a04c5 100644 --- a/with_opencm3/flash.h +++ b/with_opencm3/flash.h @@ -25,6 +25,7 @@ #include "main.h" #include "user_proto.h" +#include "onewire.h" /* * this is a default values of stored data @@ -41,6 +42,8 @@ typedef struct{ // A-D value[x] = ADU * ADC_multipliers[x] / ADC_divisors[x] uint32_t _ADC_multipliers[ADC_CHANNELS_NUMBER]; uint32_t _ADC_divisors[ADC_CHANNELS_NUMBER]; + uint8_t _OW_id_array[8][OW_MAX_NUM]; + uint8_t _OW_dev_amount; // char last_addr[0]; // we need this pointer to calculate real size of structure }stored_data; @@ -53,6 +56,8 @@ extern stored_data Stored_Data; #define ADC_multipliers Stored_Data._ADC_multipliers #define ADC_divisors Stored_Data._ADC_divisors +#define OW_id_array Stored_Data._OW_id_array +#define OW_dev_amount Stored_Data._OW_dev_amount void dump_flash_data(sendfun s); uint8_t save_flashdata(); diff --git a/with_opencm3/hardware_ini.c b/with_opencm3/hardware_ini.c index 3ad0443..b7a4320 100644 --- a/with_opencm3/hardware_ini.c +++ b/with_opencm3/hardware_ini.c @@ -137,10 +137,12 @@ void GPIO_init(){ GPIO_CNF_OUTPUT_OPENDRAIN, LED_STATUS_PIN); LED_STATUS_BAD(); // turn LED off // Shutter control: input pull up - gpio_set_mode(SHUTTER_EXT_PORT, GPIO_MODE_INPUT, - GPIO_CNF_INPUT_PULL_UPDOWN, SHUTTER_CAM_PIN | SHUTTER_MAN_PIN | SHUTTER_FBSW_PIN); - //gpio_set(SHUTTER_EXT_PORT, SHUTTER_CAM_PIN | SHUTTER_MAN_PIN | SHUTTER_FBSW_PIN); // turn on pull up - GPIO_ODR(SHUTTER_EXT_PORT) |= SHUTTER_CAM_PIN | SHUTTER_MAN_PIN | SHUTTER_FBSW_PIN; + gpio_set(SHUTTER_CAM_PORT, SHUTTER_CAM_PIN); + gpio_set(SHUTTER_MAN_PORT, SHUTTER_MAN_PIN); + gpio_set(SHUTTER_FBSW_PORT, SHUTTER_FBSW_PIN); + gpio_set_mode(SHUTTER_CAM_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, SHUTTER_CAM_PIN); + gpio_set_mode(SHUTTER_MAN_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, SHUTTER_MAN_PIN); + gpio_set_mode(SHUTTER_FBSW_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, SHUTTER_FBSW_PIN); // shutter status LED: opendrain gpio_set_mode(LED_SHUTTER_PORT, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, LED_SHUTTER_PIN); @@ -286,254 +288,3 @@ int TRD_value(uint8_t num){ return (int) r; } -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(_U_ uint8_t ow_byte, _U_ uint8_t Nbits, _U_ uint8_t ini){ - uint8_t i, byte; - if(ini) tum2buff_ctr = 0; - if(Nbits == 0) return 0; - if(Nbits > 8) Nbits = 8; - for(i = 0; i < Nbits; i++){ - if(ow_byte & 0x01){ - byte = OW_1; - }else{ - byte = OW_0; - } - tim2_buff[tum2buff_ctr++] = byte; - if(tum2buff_ctr == TIM2_DMABUFF_SIZE) return 0; // avoid buffer overflow - ow_byte = ow_byte >> 1; - } -// print_int(tum2buff_ctr, lastsendfun); -// MSG(" 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++){ - tim2_buff[tum2buff_ctr++] = 1; - if(tum2buff_ctr == TIM2_DMABUFF_SIZE) return 0; - } -#ifdef EBUG - if(mode == BYTE_MODE){ - print_int(tum2buff_ctr, lastsendfun); - P(" bytes in send buffer\n", lastsendfun); - } -#endif - return 1; -} - -/** - * Fill output buffer with data from 1-wire - * @param start_idx - index from which to start (bit number) - * @param N - data length (in **bytes**) - * @outbuf - where to place data - */ -void read_from_OWbuf(_U_ uint8_t start_idx, _U_ uint8_t N, _U_ uint8_t *outbuf){ - 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; -#ifdef EBUG - if(mode == BYTE_MODE){ - print_int(tim2_inbuff[i], lastsendfun); - lastsendfun(' '); - } -#endif - if(tim2_inbuff[i++] < OW_READ1) - 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_OPM | TIM_CR1_UDIS); // continuous mode & enable update events - TIM2_CR1 |= TIM_CR1_ARPE; // changing period immediately - TIM2_ARR = OW_BIT; // default period of timer - // 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 CC4 & 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; - /* - DMA1_CCR7 |= DMA_CCR_DIR; // dma_set_read_from_memory(DMA1, DMA_CHANNEL7); - DMA1_CCR7 |= DMA_CCR_MINC; // dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL7); - //dma_disable_peripheral_increment_mode(DMA1, DMA_CHANNEL7); - DMA1_CCR7 |= DMA_CCR_PSIZE_16BIT; // dma_set_peripheral_size(DMA1, DMA_CHANNEL7, DMA_CCR_PSIZE_16BIT); - DMA1_CCR7 |= DMA_CCR_MSIZE_16BIT; // dma_set_memory_size(DMA1, DMA_CHANNEL7, DMA_CCR_MSIZE_16BIT); - DMA1_CCR7 |= DMA_CCR_TEIE; // dma_enable_transfer_error_interrupt(DMA1, DMA_CHANNEL7); - DMA1_CCR7 |= DMA_CCR_TCIE; // dma_enable_transfer_complete_interrupt(DMA1, DMA_CHANNEL7); - */ - nvic_enable_irq(NVIC_DMA1_CHANNEL7_IRQ); // enable dma1_channel7_isr -} - -void run_dmatimer(){ - ow_done = 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 - - //init_ow_dmatimer(); -/* - // TIM2_CH4 - DMA1, channel 7 - dma_channel_reset(DMA1, DMA_CHANNEL7); - dma_set_read_from_memory(DMA1, DMA_CHANNEL7); - dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL7); - dma_disable_peripheral_increment_mode(DMA1, DMA_CHANNEL7); - dma_set_peripheral_size(DMA1, DMA_CHANNEL7, DMA_CCR_PSIZE_16BIT); - dma_set_memory_size(DMA1, DMA_CHANNEL7, DMA_CCR_MSIZE_16BIT); - dma_enable_transfer_error_interrupt(DMA1, DMA_CHANNEL7); - dma_enable_transfer_complete_interrupt(DMA1, DMA_CHANNEL7); - */ - 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; // dma_set_memory_address(DMA1, DMA_CHANNEL7, (uint32_t)tim2_buff); - DMA1_CNDTR7 = tum2buff_ctr;//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; - /* - dma_set_read_from_peripheral(DMA1, DMA_CHANNEL1); - dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL1); - dma_disable_peripheral_increment_mode(DMA1, DMA_CHANNEL1); - dma_set_peripheral_size(DMA1, DMA_CHANNEL1, DMA_CCR_PSIZE_16BIT); - dma_set_memory_size(DMA1, DMA_CHANNEL1, DMA_CCR_MSIZE_16BIT); - dma_enable_transfer_error_interrupt(DMA1, DMA_CHANNEL1); - dma_enable_transfer_complete_interrupt(DMA1, DMA_CHANNEL1); - */ - 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_CR1 &= ~TIM_CR1_OPM; // continuous mode - TIM2_ARR = OW_BIT; // bit length - TIM2_EGR = TIM_EGR_UG; // update value of ARR - - TIM2_CR2 &= ~TIM_CR2_CCDS; // timer_set_dma_on_compare_event(TIM2); - TIM2_CCER |= TIM_CCER_CC3E; // enable input capture - TIM2_DIER = TIM_DIER_CC4DE | TIM_DIER_CC3DE; // enable DMA events - // set low polarity, enable cc out & enable input capture - TIM2_CCER |= TIM_CCER_CC4P | TIM_CCER_CC4E | TIM_CCER_CC3E; - TIM2_CR1 |= TIM_CR1_CEN; // run timer - -} - -uint16_t rstat = 0, lastcc3; -void ow_reset(){ - ow_done = 0; - rstat = 0; - TIM2_SR = 0; // clear all flags - TIM2_DIER = 0; // disable timer interrupts - TIM2_ARR = OW_RESET_TIME; // set period to 1ms - TIM2_CCR4 = OW_RESET; // zero pulse length - TIM2_EGR = TIM_EGR_UG; // update values of ARR & CCR4 - TIM2_CR1 |= TIM_CR1_OPM | TIM_CR1_CEN; // we need only single pulse & run timer - TIM2_SR = 0; // clear update flag generated after timer's running - TIM2_DIER = TIM_DIER_UIE | TIM_DIER_CC3IE; // generate interrupts on update event & cc - nvic_enable_irq(NVIC_TIM2_IRQ); -} - -void tim2_isr(){ - if(TIM2_SR & TIM_SR_UIF){ // update interrupt - TIM2_SR &= ~TIM_SR_UIF; // clear flag - TIM2_DIER = 0; // disable all timer interrupts - TIM2_CCR4 = 0; // set output value to 1 - TIM2_EGR |= TIM_EGR_UG; // generate update event to change value in CCR4 - TIM2_CR1 &= ~TIM_CR1_CEN; // timer_disable_counter(TIM2); - nvic_disable_irq(NVIC_TIM2_IRQ); - ow_done = 1; - rstat = lastcc3; -/* print_int(rstat, lastsendfun); - MSG("\n");*/ - } - if(TIM2_SR & TIM_SR_CC3IF){ // we need this interrupt to store CCR3 value - TIM2_SR = 0; // clear flag (we've manage TIM_SR_UIF before, so can simply do =0) - lastcc3 = TIM2_CCR3; - //TIM2_DIER &= ~TIM_DIER_CC3IE; // disable CCR3 interrupts - } -} - - -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 - //TIM2_DIER &= ~TIM_DIER_CC4DE; - }else if(DMA1_ISR & DMA_ISR_TEIF7){ - DMA1_IFCR = DMA_IFCR_CTEIF7; - DBG("DMA out transfer error\n"); - } -} - -void dma1_channel1_isr(){ - //int i; - if(DMA1_ISR & DMA_ISR_TCIF1) { - DMA1_IFCR = DMA_IFCR_CTCIF1; - TIM2_CR1 &= ~TIM_CR1_CEN; // timer_disable_counter(TIM2); - //TIM2_DIER &= ~TIM_DIER_CC3DE; - 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], lastsendfun); - MSG(" "); - } - MSG("\n");*/ - }else if(DMA1_ISR & DMA_ISR_TEIF1){ - DMA1_IFCR = DMA_IFCR_CTEIF1; - DBG("DMA in transfer error\n"); - } -} - -uint8_t OW_get_reset_status(){ -/* print_int(rstat, lastsendfun); - MSG("\n");*/ - if(rstat < OW_PRESENT) return 0; // no devices - return 1; -} - diff --git a/with_opencm3/hardware_ini.h b/with_opencm3/hardware_ini.h index 25784cc..ae62700 100644 --- a/with_opencm3/hardware_ini.h +++ b/with_opencm3/hardware_ini.h @@ -34,16 +34,6 @@ */ -#define TIM2_DMABUFF_SIZE 128 -// 1-wire zero-state lengths (in us minus 1) -#define OW_1 (9) -#define OW_0 (69) -#define OW_READ1 (14) -#define OW_BIT (79) -#define OW_RESET (499) -#define OW_RESET_TIME (999) -#define OW_PRESENT (549) - extern volatile uint16_t ADC_value[]; // ADC DMA value #define TRD_NO (8) // number of TRD devices @@ -60,6 +50,8 @@ void SysTick_init(); void ADC_init(); void ADC_calibrate_and_start(); +void adc_dma_on(); + /* * USB interface */ @@ -104,22 +96,27 @@ void ADC_calibrate_and_start(); /* * One Wire interface - */ + * // In case of using other USART for 1-wire port, make corresponding change // and redefine pins in OW_Init #define OW_USART_X USART2 #define OW_RX_PORT GPIO_BANK_USART2_RX #define OW_RX_PIN GPIO_USART2_RX - +*/ /* * Shutter defines */ // external signals for shutter opening: PB3 (SPI1_SCK) - from camera electronics, PB4 (SPI1_MISO) - from manual switch // both are pull-up inputs -#define SHUTTER_EXT_PORT (GPIOB) -#define SHUTTER_CAM_PIN (GPIO3) +//#define SHUTTER_CAM_PORT (GPIOB) +//#define SHUTTER_CAM_PIN (GPIO3) +// As PB3 was burned, redefine CAM to EXT0 - PD10 +#define SHUTTER_CAM_PORT (GPIOD) +#define SHUTTER_CAM_PIN (GPIO10) +#define SHUTTER_MAN_PORT (GPIOB) #define SHUTTER_MAN_PIN (GPIO4) // shutter feedback ==0 when opened, PB5 (SPI1_MOSI) +#define SHUTTER_FBSW_PORT (GPIOB) #define SHUTTER_FBSW_PIN (GPIO5) // LED status open-drain output: PB8 (CAN RX) #define LED_STATUS_PORT (GPIOB) @@ -153,15 +150,4 @@ int shutter_voltage(); int power_voltage(); int TRD_value(uint8_t num); -void init_ow_dmatimer(); -void run_dmatimer(); -extern uint8_t ow_done; -#define OW_READY() (ow_done) -void ow_dma_on(); -void adc_dma_on(); -uint8_t OW_add_byte(uint8_t ow_byte, uint8_t Nbits, uint8_t ini); -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(); #endif // __HARDWARE_INI_H__ diff --git a/with_opencm3/ircontroller.bin b/with_opencm3/ircontroller.bin index e920edd..11f80dd 100755 Binary files a/with_opencm3/ircontroller.bin and b/with_opencm3/ircontroller.bin differ diff --git a/with_opencm3/main.c b/with_opencm3/main.c index 4514876..e264dfc 100644 --- a/with_opencm3/main.c +++ b/with_opencm3/main.c @@ -24,11 +24,19 @@ #include "cdcacm.h" #include "uart.h" #include "spi.h" +//#include "stepper_motors.h" + +#include "sync.h" +#include "flash.h" +#include "AD7794.h" +#include "onewire.h" #include "stepper_motors.h" +#include "powerhw.h" volatile uint32_t Timer = 0, tOVRFL = 0; // global timer (milliseconds), overflow counter usbd_device *usbd_dev; +uint8_t OW_scan = 1; uint8_t ADC_monitoring = 0; // ==1 to make continuous monitoring uint32_t ad7794_on = 0; @@ -135,9 +143,30 @@ void AD7794_init(){ } } +void scan_onewire(){ + if(!OW_get_reset_status()){ // try to send read sequence if there wasn't any 1-wire devices + int i; + for(i = 0; i < OW_dev_amount; ++i) + OW_temperature[i] = ERR_TEMP_VAL; + OW_send_read_seq(); + return; + } + if(OW_MEASUREMENTS_DONE()){ + OW_CLEAR_DONE_FLAG(); + OW_read_next_temp(); + } + if(OW_DATA_READY()){ + OW_CLEAR_READY_FLAG(); + if(OW_current_num() == OW_dev_amount - 1) + OW_send_read_seq(); + else + OW_read_next_temp(); + } +} + int main(){ //int i; - uint32_t Shtr_blink_timer = 0, Old_timer = 0, lastTRDread = 0, lastTmon = 0; + uint32_t Shtr_blink_timer = 0, Old_timer = 0, lastTRDread = 0, lastTmon = 0, OW_timer = 0; int oldusbdatalen = 0; //SPI_read_status SPI_stat; @@ -149,7 +178,6 @@ int main(){ // GPIO GPIO_init(); - usb_disconnect(); // turn off USB while initializing all // init USART3 (master) & USART1 (slave) @@ -166,7 +194,6 @@ int main(){ // SPI2 used for working with external ADC switch_SPI(SPI2); // init SPI2 SPI_init(); - init_ow_dmatimer(); // wait a little and then turn on USB pullup // for (i = 0; i < 0x800000; i++) @@ -183,6 +210,9 @@ int main(){ read_stored_data(); // copy stored data into RAM + init_ow_dmatimer(); + //OW_send_read_seq(); + LED_STATUS_OK(); // All initialized - light up LED while(1){ usbd_poll(usbd_dev); @@ -199,11 +229,10 @@ int main(){ } } OW_process(); // process 1-wire commands - if(OW_DATA_READY()){ - OW_CLEAR_READY_FLAG(); -#ifdef EBUG - OW_printID(0, lastsendfun); -#endif + // scan 1-wire each 1 second + if(OW_scan && (Timer - OW_timer > 999 || Timer < OW_timer)){ + OW_timer = Timer; + scan_onewire(); } process_stepper_motors(); // check flags of motors' timers process_shutter(); // shutter state machine @@ -221,12 +250,6 @@ int main(){ if(Shutter_State == SHUTTER_NOTREADY){ shutter_init(); } -//OW_fill_ID(0); - //gpio_toggle(GPIOC, GPIO12); // toggle LED - //gpio_toggle(GPIO_BANK_SPI2_MOSI, GPIO_SPI2_MOSI); - //gpio_toggle(GPIO_BANK_SPI2_SCK, GPIO_SPI2_SCK); - // if(!ad7794_on) AD7794_init(); // try to init ADC if it doesn't work - //print_int(Timer/1000, usb_send); }else if(Timer < Old_timer){ // Timer overflow Old_timer = 0; tOVRFL++; // this is an overflow counter - for workinkg in long-long time interval diff --git a/with_opencm3/main.h b/with_opencm3/main.h index 311fd96..d8c70df 100644 --- a/with_opencm3/main.h +++ b/with_opencm3/main.h @@ -36,17 +36,12 @@ #include #include #include +#include + +#include "user_proto.h" #define ADC_CHANNELS_NUMBER (10) -#include "sync.h" // mutexes -#include "flash.h" -#include "user_proto.h" -#include "AD7794.h" -#include "onewire.h" -#include "stepper_motors.h" -#include "powerhw.h" - #define _U_ __attribute__((__unused__)) #define U8(x) ((uint8_t) x) #define U16(x) ((uint16_t) x) @@ -56,6 +51,7 @@ extern uint32_t ad7794_values[]; // array with ADC data extern uint8_t doubleconv; // single/double ADC conversion extern uint32_t ad7794_on; // ==1 after AD7794 initialisation extern uint8_t ADC_monitoring; // ==1 to make continuous monitoring +extern uint8_t OW_scan; void AD7794_init(); extern volatile uint32_t Timer; // global timer (milliseconds) diff --git a/with_opencm3/onewire.c b/with_opencm3/onewire.c index bb46cef..ae81e5f 100644 --- a/with_opencm3/onewire.c +++ b/with_opencm3/onewire.c @@ -18,9 +18,10 @@ */ #include "onewire.h" #include "user_proto.h" +#include "hardware_ini.h" +#include "flash.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 +//OW_ID id_array[OW_MAX_NUM]; // 1-wire devices ID buffer (not more than eight) // states of 1-wire processing queue typedef enum{ @@ -29,34 +30,224 @@ typedef enum{ OW_SEND_STATE, // send data OW_READ_STATE, // wait for reading } OW_States; +static volatile OW_States OW_State = OW_OFF_STATE; // 1-wire state, 0-not runned + +void (*ow_process_resdata)() = NULL; +void wait_reading(); + +static uint16_t tim2_buff[TIM2_DMABUFF_SIZE]; +static uint16_t tim2_inbuff[TIM2_DMABUFF_SIZE]; +int tum2buff_ctr = 0; +uint8_t ow_done = 1; +uint8_t ow_measurements_done = 0; + +/** + * 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; + } + 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; + } + 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; + if(tim2_inbuff[i++] < ONE_ZERO_BARRIER) + byte |= 0x80; + } + *outbuf++ = byte; + } +} +// 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 + 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"); +} + +void run_dmatimer(){ + ow_done = 0; + TIM2_CR1 = 0; + adc_disable_dma(ADC1); // turn off DMA & ADC + adc_off(ADC1); + // TIM2_CH4 - DMA1, channel 7 + 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_CH3 - DMA1, channel 1 + 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 +} + +uint16_t rstat = 0, lastcc3 = 3; +void ow_reset(){ + 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_DIER = TIM_DIER_CC3IE; + 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 + TIM2_CCR4 = 0; // set output value to 1 + TIM2_EGR = TIM_EGR_UG; // update values of ARR & CCR4 + nvic_disable_irq(NVIC_TIM2_IRQ); + TIM2_SR = 0; // clear flag + ow_done = 1; + rstat = lastcc3; + } + 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(){ + if(DMA1_ISR & DMA_ISR_TCIF1){ + 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; + }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; +} -OW_States OW_State = OW_OFF_STATE; // 1-wire state, 0-not runned -uint8_t OW_wait_bytes = 0; // amount of bytes needed to read -uint8_t OW_start_idx = 0; // starting index to read from 1-wire buffer -uint8_t *read_buf = NULL; // buffer to read uint8_t ow_data_ready = 0; // flag of reading OK -void OW_printID(uint8_t N, sendfun s){ - void putc(uint8_t c){ - if(c < 10) - s(c + '0'); - else - s(c + 'a' - 10); - } - int i; - uint8_t *b = id_array[N].bytes; - s('0'); s('x'); // prefix 0x - for(i = 0; i < 8; i++){ - putc(b[i] >> 4); - putc(b[i] & 0x0f); - } - s('\n'); -} - -uint8_t ow_was_reseting = 0; - +/** + * 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; @@ -65,61 +256,82 @@ void OW_process(){ OW_State = OW_SEND_STATE; ow_was_reseting = 1; ow_reset(); - //MSG("reset\n"); break; case OW_SEND_STATE: - if(!OW_READY()) return; // reset in work + if(!ow_done) return; // reset in work if(ow_was_reseting){ - if(!OW_get_reset_status()){ - BYTE_MSG("error: no 1-wire devices found\n"); + if(rstat < RESET_BARRIER){ + ERR("Error: no 1-wire devices found\n"); ow_was_reseting = 0; - // OW_State = OW_OFF_STATE; - // return; + OW_State = OW_OFF_STATE; + return; } } ow_was_reseting = 0; OW_State = OW_READ_STATE; run_dmatimer(); // turn on data transfer - //MSG("send\n"); break; case OW_READ_STATE: - if(!OW_READY()) return; // data isn't ready + 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(read_buf){ - read_from_OWbuf(OW_start_idx, OW_wait_bytes, read_buf); - } + adc_start_conversion_regular(ADC1); + adc_start_conversion_direct(ADC1); + if(ow_process_resdata) + ow_process_resdata(); ow_data_ready = 1; - //MSG("read\n"); break; } } + +static uint8_t *read_buf = NULL; // buffer for storing readed data +/** + * fill ID buffer with readed data + */ +void fill_buff_with_data(){ + ow_process_resdata = NULL; + if(!read_buf) return; + read_from_OWbuf(1, 8, read_buf); + int i, j; + LP("Readed ID: "); + for(i = 0; i < 8; ++i){ + print_hex(&read_buf[i], 1, lastsendfun); + lastsendfun(' '); + } + lastsendfun('\n'); + // now check stored ROMs + for(i = 0; i < OW_dev_amount; ++i){ + uint8_t *ROM = OW_id_array[i]; + for(j = 0; j < 8; j++) + if(ROM[j] != read_buf[j]) break; + if(j == 8){ // we found this cell + ERR("Such ID exists\n"); + goto ret; + } + } + ++OW_dev_amount; +ret: + read_buf = NULL; +} + /** * fill Nth array with identificators */ //uint8_t comtosend = 0; -void OW_fill_ID(uint8_t N){ - if(N >= OW_MAX_NUM){ - BYTE_MSG("number too big\n"); +void OW_fill_next_ID(){ + if(OW_dev_amount >= OW_MAX_NUM){ + ERR("No memory left for new device\n"); return; } - //OW_Send(1, (uint8_t*)"\xcc\x33", 2); - OW_Send(1, (uint8_t*)"\x19", 1); -// OW_Send(1, &comtosend, 1); -// comtosend++; - //OW_Send(1, (uint8_t*)"\xcc\xbe", 2); - OW_add_read_seq(9); // wait for 9 bytes - //OW_Send(0, (uint8_t*)"\xcc\x33\x10\x45\x94\x67\x7e\x8a", 8); - read_buf = id_array[N].bytes; - OW_wait_bytes = 8; - OW_start_idx = 0; -/* - OW_Send(0, (uint8_t*)"\x99\xee", 2); - OW_wait_bytes = 2; - OW_start_idx = 0; - read_buf = id_array[N].bytes; -*/ + 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 = OW_id_array[OW_dev_amount]; + ow_process_resdata = fill_buff_with_data; + DBG("wait for ID\n"); } /** @@ -131,112 +343,132 @@ void OW_fill_ID(uint8_t N){ * @return 1 if succeed, 0 if failure */ uint8_t OW_Send(uint8_t sendReset, uint8_t *command, uint8_t cLen){ - uint8_t f = 1; 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, 8, f)) return 0; - command++; - f = 0; + if(!OW_add_byte(*command++)) return 0; } return 1; } - -#if 0 - - -void OW_ClearBuff(){ - UART_buff *curbuff = get_uart_buffer(OW_USART_X); - curbuff->end = 0; -} - -/* - * Inverce conversion - read data (not more than 8 bits) - */ -uint8_t OW_ConvertByte(uint8_t *bits, uint8_t L){ - uint8_t ow_byte = 0, i, *st = bits; - if(L > 8) L = 8; // forget all other data - for(i = 0; i < L; i++, st++){ - ow_byte = ow_byte >> 1; // prepare for next bit filling - if(*st == OW_1){ - ow_byte |= 0x80; // MSB = 1 - } - } - ow_byte >>= (8 - L); -print_hex(bits, L, lastsendfun); -lastsendfun(' '); -print_hex(&ow_byte, 1, lastsendfun); -newline(lastsendfun); - return ow_byte; // shift to the end: L could be != 8 ??? -} - - - - -/* - * 1-wire reset - * Reset procedure: USART settings are 9600,8,n,1, - * send 0xf0 then check what we get - * if not 0xf0 line is busy. - * Other operations work with next USART settings: 115200,8,n,1 - * - * return 1 in case of 1-wire devices present; otherwise return 0 - */ -uint8_t OW_Reset(){ - uint8_t ow_presence; - UART_buff *curbuff; - // change speed to 9600 - usart_set_baudrate(OW_USART_X, 9600); - //USART_ClearFlag(OW_USART_X, USART_FLAG_TC); - fill_uart_buff(OW_USART_X, OW_RST); // send 1 byte data - // wait for end of transmission - while(!(USART_SR(OW_USART_X) & USART_SR_TC)); - curbuff = get_uart_buffer(OW_USART_X); - if(!curbuff || !(curbuff->end)) return 0; // error reading - curbuff->end = 0; // zero counter - ow_presence = curbuff->buf[0]; - // change speed back - usart_set_baudrate(OW_USART_X, 115200); - // if there is any device on bus, it will pull it, so we'll get not 0xf0 - if(ow_presence != OW_RST){ - return 1; - } - // we get 0xf0 -> there's nothing on the bus - return 0; -} - - - /** - * Check USART IN buffer for ready & fill user buffer with data on success - * @param buflen - expected buffer length - * @param data - pointer for reading buffer (if reading needed must be at least buflen-readStart bytes) - * @param readStart - first byte to read (starts from 0) or OW_NO_READ (not read) - * @return 0 if buffer not ready; 1 if OK + * 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 */ -uint8_t OW_Get(uint8_t buflen, uint8_t *data, uint8_t readStart){ - UART_buff *curbuff = get_uart_buffer(OW_USART_X); - uint8_t *buff = curbuff->buf; - if(curbuff->end < buflen/8) return 0; - while(buflen-- > 0){ - if(readStart == 0){ - *data++ = OW_ConvertByte(buff, 8); - }else{ - if(readStart != OW_NO_READ){ - readStart--; - } - } - buff += 8; +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{ // DS18B20 + 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 } - curbuff->end = 0; // zero counter - return 1; + return t; } +int32_t OW_temperature[OW_MAX_NUM]; +int8_t Ncur = -1; +/** + * get temperature from buffer + */ +void convert_next_temp(){ + uint8_t scratchpad[9], idx = Ncur; + ow_process_resdata = NULL; + if(OW_dev_amount < 2){ + idx = 0; + read_from_OWbuf(2, 9, scratchpad); + }else{ + read_from_OWbuf(10, 9, scratchpad); + } + OW_temperature[idx] = gettemp(scratchpad); +#ifdef EBUG + if(mode == BYTE_MODE){ + LP("T["); + print_int(idx, lastsendfun); + LP("] = "); + print_int(OW_temperature[idx], lastsendfun); + LP("/10 degrC\n"); + } +#endif +} + +/** + * read next stored thermometer + */ +void OW_read_next_temp(){ + ow_data_ready = 0; + OW_State = OW_RESET_STATE; + OW_reset_buffer(); + int i; + if(OW_dev_amount < 2){ + Ncur = -1; + OW_add_byte(OW_SKIP_ROM); + }else{ + if(++Ncur >= OW_dev_amount) Ncur = 0; + OW_add_byte(OW_MATCH_ROM); + uint8_t *ROM = OW_id_array[Ncur]; + 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 wait_reading(){ + uint8_t bt; + read_from_OWbuf(0, 1, &bt); + if(bt == 0xff){ // the conversion is done! + ow_measurements_done = 1; + ow_process_resdata = NULL; + DBG("Measurements done!\n"); + }else{ + OW_State = OW_SEND_STATE; + OW_reset_buffer(); + ow_data_ready = 0; + OW_add_read_seq(1); // send read seq waiting for end of conversion + } +} + +void OW_send_read_seq(){ + ow_data_ready = 0; + ow_measurements_done = 0; + OW_State = OW_RESET_STATE; + OW_reset_buffer(); + OW_add_byte(OW_SKIP_ROM); + OW_add_byte(OW_CONVERT_T); + OW_add_read_seq(1); // send read seq waiting for end of conversion + ow_process_resdata = wait_reading; +} /* * scan 1-wire bus * WARNING! The procedure works in real-time, so it is VERY LONG @@ -285,47 +517,3 @@ uint8_t OW_Scan(uint8_t *buf, uint8_t num){ return cnt_num; }*/ -uint8_t OW_Scan(uint8_t *buf, uint8_t num){ - uint8_t flg, b[11], i; - flg = OW_Send(1, (uint8_t*)"\xcc\x33\xff\xff\xff\xff\xff\xff\xff\xff\xff", 11); - if(!flg) return 0; - OW_Wait_TX(); - if(!OW_Get(11, b, 0)) return 0; - num += 2; - for(i = 2; i < num; i++) *buf++ = b[i]; - return 1; -} - - -//OW_USART_X -/* -void OW_getTemp(){ - uint8_t buf[9], i; - void printTBuf(){ - uint8_t j; - OW_Send(0, (uint8_t*)"\xbe\xff\xff\xff\xff\xff\xff\xff\xff\xff", 10, buf, 9, 1); - for(j = 0; j != 9; j++) - printInt(&buf[j], 1); - newline(); - } - // send broadcast message to start measurement - if(!OW_Send(1, (uint8_t*)"\xcc\x44", 2)) return; - Delay(1000); - // read values - if(dev_amount == 1){ - if(OW_WriteCmd(OW_SKIP_ROM)) printTBuf(); - }else{ - for(i = 0; i < dev_amount; i++){ - MSG("Device ", "ow"); - USB_Send_Data(i + '0'); - MSG(": ", 0); - if(OW_WriteCmd(OW_MATCH_ROM)){ - OW_SendOnly(0, &ID_buf[i*8], 8); - printTBuf(); - } - } - } -} -*/ - -#endif diff --git a/with_opencm3/onewire.h b/with_opencm3/onewire.h index f46c092..67b7d7e 100644 --- a/with_opencm3/onewire.h +++ b/with_opencm3/onewire.h @@ -24,51 +24,95 @@ #include "main.h" #include "hardware_ini.h" -// 1-wire status -#define OW_OK (1) -#define OW_ERROR (2) -#define OW_NO_DEVICE (3) +// 20 bytes x 8bits +#define TIM2_DMABUFF_SIZE 160 -#define OW_NO_READ (0xff) - -#define OW_READ_SLOT (uint8_t*)"0xff" +// freq = 1MHz +// ARR values: 1000 for reset, 100 for data in/out +// CCR4 values: 500 for reset, 60 for sending 0 or reading, <15 for sending 1 +// CCR3 values: >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 ((int32_t)200000) +/* typedef struct{ uint8_t bytes[8]; } OW_ID; - +*/ #define OW_MAX_NUM 8 +//extern OW_ID id_array[]; + +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; +extern uint8_t ow_measurements_done; #define OW_DATA_READY() (ow_data_ready) #define OW_CLEAR_READY_FLAG() do{ow_data_ready = 0;}while(0) +#define OW_MEASUREMENTS_DONE() (ow_measurements_done) +#define OW_CLEAR_DONE_FLAG() do{ow_measurements_done = 0;}while(0) void OW_process(); -void OW_fill_ID(uint8_t N); +void OW_fill_next_ID(); +void OW_send_read_seq(); uint8_t OW_Send(uint8_t sendReset, uint8_t *command, uint8_t cLen); -void OW_printID(uint8_t N, sendfun s); +extern int32_t OW_temperature[]; +extern int8_t Ncur; +void OW_read_next_temp(); +#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) -#if 0 - - -uint8_t OW_Get(uint8_t buflen, uint8_t *data, uint8_t readStart); -uint8_t OW_Scan(uint8_t *buf, uint8_t num); - -// shortcuts for functions -// only send message b wich length is c with RESET flag a -#define OW_SendOnly(a,b,c) OW_Send(a, b, c) -// send 1 command (with bus reset) -#define OW_WriteCmd(cmd) OW_Send(1, cmd, 1) -// send 1 function (without bus reset) -#define OW_WriteFn(cmd) OW_Send(0, cmd, 1) -#define OW_Wait_TX() while(!(USART_SR(OW_USART_X) & USART_SR_TC)) - -void OW_getTemp(); - - -#endif /* * thermometer identificator is: 8bits CRC, 48bits serial, 8bits device code (10h) @@ -78,48 +122,6 @@ void OW_getTemp(); * format T_H and T_L: 1bit sigh + 7bits of data */ -/* - * thermometer commands (DS18S20)\ - * send them with bus reset! - */ -// find devices -#define T_SEARCH_ROM (0xf0) -#define OW_SEARCH_ROM (uint8_t*)"\xf0" -// read device (when it is alone on the bus) -#define T_READ_ROM (0x33) -#define OW_READ_ROM (uint8_t*)"\x33" -// send device ID (after this command - 8 bytes of ID) -#define T_MATCH_ROM (0x55) -#define OW_MATCH_ROM (uint8_t*)"\x55" -// broadcast command -#define T_SKIP_ROM (0xcc) -#define OW_SKIP_ROM (uint8_t*)"\xcc" -// find devices with critical conditions -#define T_ALARM_SEARCH (0xec) -#define OW_ALARM_SEARCH (uint8_t*)"\xec" -/* - * thermometer functions - * send them without bus reset! - */ -// start themperature reading -#define T_CONVERT_T (0x44) -#define OW_CONVERT_T (uint8_t*)"\x44" -// write critical temperature to device's RAM -#define T_SCRATCHPAD (0x4e) -#define OW_SCRATCHPAD (uint8_t*)"\x4e" -// read whole device flash -#define T_READ_SCRATCHPAD (0xbe) -#define OW_READ_SCRATCHPAD (uint8_t*)"\xbe" -// copy critical themperature from device's RAM to its EEPROM -#define T_COPY_SCRATCHPAD (0x48) -#define OW_COPY_SCRATCHPAD (uint8_t*)"\x48" -// copy critical themperature from EEPROM to RAM (when power on this operation runs automatically) -#define T_RECALL_E2 (0xb8) -#define OW_RECALL_E2 (uint8_t*)"\xb8" -// check whether there is devices wich power up from bus -#define T_READ_POWER_SUPPLY (0xb4) -#define OW_READ_POWER_SUPPLY (uint8_t*)"\xb4" - /* * RAM register: diff --git a/with_opencm3/powerhw.c b/with_opencm3/powerhw.c index 91c59e5..6745f84 100644 --- a/with_opencm3/powerhw.c +++ b/with_opencm3/powerhw.c @@ -20,6 +20,8 @@ */ #include "main.h" +#include "powerhw.h" + // state of shutter - global variable to omit interface functions shutter_state Shutter_State = SHUTTER_NOTREADY; int8_t manual_pin_old_state = -1; @@ -148,7 +150,7 @@ void shutter_test(){ void shutter_ready(){ uint8_t test_err = 0; //DBG("shtr ready\n"); - uint32_t shtr_status = gpio_get(SHUTTER_EXT_PORT, SHUTTER_FBSW_PIN); // 0 when opened + uint32_t shtr_status = gpio_get(SHUTTER_FBSW_PORT, SHUTTER_FBSW_PIN); // 0 when opened switch (Shutter_State){ case SHUTTER_CLOSED: // repeated pulse to check errors if(shtr_status) @@ -235,14 +237,9 @@ shutter_state shutter_init(){ // feedback: floating input gpio_set_mode(SHUTTER_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, SHUTTER_FB_PIN); - // Shutter control: input pull up -// gpio_set_mode(SHUTTER_EXT_PORT, GPIO_MODE_INPUT, -// GPIO_CNF_INPUT_FLOAT, SHUTTER_CAM_PIN | SHUTTER_MAN_PIN | SHUTTER_FBSW_PIN); -// gpio_set(SHUTTER_EXT_PORT, SHUTTER_CAM_PIN | SHUTTER_MAN_PIN | SHUTTER_FBSW_PIN); // turn on pull up - //DBG("shutter fb ready\n"); shutter_off(); - camera_pin_old_state = (gpio_get(SHUTTER_EXT_PORT, SHUTTER_CAM_PIN)) ? 1 : 0; - manual_pin_old_state = (gpio_get(SHUTTER_EXT_PORT, SHUTTER_MAN_PIN)) ? 1 : 0; + camera_pin_old_state = (gpio_get(SHUTTER_CAM_PORT, SHUTTER_CAM_PIN)) ? 1 : 0; + manual_pin_old_state = (gpio_get(SHUTTER_MAN_PORT, SHUTTER_MAN_PIN)) ? 1 : 0; //shutter_timer_fn = NULL; shutter_wait_block(SHUTTER_OP_DELAY, shutter_test); return SHUTTER_INITIALIZED; // we return this state in spite of the shutter isn't really initialized yet @@ -260,7 +257,7 @@ void process_shutter(){ if(Shutter_State == SHUTTER_NOTREADY) return; // test state of external control pins - cam_pin_state = (gpio_get(SHUTTER_EXT_PORT, SHUTTER_CAM_PIN)) ? 1 : 0; + cam_pin_state = (gpio_get(SHUTTER_CAM_PORT, SHUTTER_CAM_PIN)) ? 1 : 0; if(camera_pin_old_state != cam_pin_state){ // camera signal changed or initialisation camera_pin_old_state = cam_pin_state; if(cam_pin_state){ // close @@ -269,7 +266,7 @@ void process_shutter(){ ext_open = 1; } } - man_pin_state = (gpio_get(SHUTTER_EXT_PORT, SHUTTER_MAN_PIN)) ? 1 : 0; + man_pin_state = (gpio_get(SHUTTER_MAN_PORT, SHUTTER_MAN_PIN)) ? 1 : 0; // to avoid opening shutter if user forget to set manual switch to "closed" position // all operations with manual switch processed only in changing state of the switch if(manual_pin_old_state != man_pin_state){ // user changed switch state -> open/close @@ -377,7 +374,7 @@ void print_shutter_state(sendfun s){ P("not initialised or broken", s); } P(" (reed ", s); - if(gpio_get(SHUTTER_EXT_PORT, SHUTTER_FBSW_PIN)){ // closed + if(gpio_get(SHUTTER_FBSW_PORT, SHUTTER_FBSW_PIN)){ // closed P("closed", s); }else{//opened P("opened", s); @@ -387,9 +384,9 @@ void print_shutter_state(sendfun s){ #ifdef EBUG if(mode == BYTE_MODE){ P("MAN: ",s); - if(gpio_get(SHUTTER_EXT_PORT, SHUTTER_MAN_PIN)) P("not ",s); + if(gpio_get(SHUTTER_MAN_PORT, SHUTTER_MAN_PIN)) P("not ",s); P("pressed, EXT: ",s); - if(gpio_get(SHUTTER_EXT_PORT, SHUTTER_CAM_PIN)) P("not ",s); + if(gpio_get(SHUTTER_CAM_PORT, SHUTTER_CAM_PIN)) P("not ",s); P("pressed\n", s); } #endif diff --git a/with_opencm3/stepper_motors.c b/with_opencm3/stepper_motors.c index 0ea6c17..fff91aa 100644 --- a/with_opencm3/stepper_motors.c +++ b/with_opencm3/stepper_motors.c @@ -20,6 +20,7 @@ */ #include "main.h" #include "stepper_motors.h" +#include "hardware_ini.h" // TODO: function "move motor to given position" diff --git a/with_opencm3/uart.c b/with_opencm3/uart.c index 7ab75c4..28c42cf 100644 --- a/with_opencm3/uart.c +++ b/with_opencm3/uart.c @@ -22,6 +22,7 @@ #include "main.h" #include "uart.h" #include "cdcacm.h" +#include "hardware_ini.h" // Buffers for Tx static UART_buff TX_buffer[3]; // Tx buffers for all three ports @@ -74,7 +75,7 @@ void UART_setspeed(uint32_t UART, struct usb_cdc_line_coding *lc){ void UART_init(uint32_t UART){ uint32_t irq, rcc, rccgpio, gpioport, gpiopin; switch(UART){ - case USART2: // 1-wire +/* case USART2: // 1-wire irq = NVIC_USART2_IRQ; // interrupt for given USART rcc = RCC_USART2; // RCC timing of USART rccgpio = RCC_GPIOA; // RCC timing of GPIO pin (for output) @@ -85,7 +86,7 @@ void UART_init(uint32_t UART){ // output pin setup gpioport = GPIO_BANK_USART2_TX; gpiopin = GPIO_USART2_TX; - break; + break;*/ case USART3: // without remapping irq = NVIC_USART3_IRQ; rcc = RCC_USART3; @@ -114,17 +115,17 @@ void UART_init(uint32_t UART){ rcc_periph_clock_enable(rcc); // USART rcc_periph_clock_enable(rccgpio); // GPIO pins // enable output pin - if(UART == OW_USART_X){ // one wire +/* if(UART == OW_USART_X){ // one wire // TX: open-drain output gpio_set_mode(gpioport, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, gpiopin); // RX: floating input gpio_set_mode(OW_RX_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, OW_RX_PIN); - }else{ + }else{*/ gpio_set_mode(gpioport, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, gpiopin); - } + //} // enable IRQ nvic_enable_irq(irq); UART_setspeed(UART, NULL); @@ -181,10 +182,10 @@ void UART_isr(uint32_t UART){ // particular interrupt handlers void usart1_isr(){ UART_isr(USART1); -} +}/* void usart2_isr(){ UART_isr(USART2); -} +}*/ void usart3_isr(){ UART_isr(USART3); } diff --git a/with_opencm3/user_proto.c b/with_opencm3/user_proto.c index 285be34..a967e79 100644 --- a/with_opencm3/user_proto.c +++ b/with_opencm3/user_proto.c @@ -24,6 +24,9 @@ #include "uart.h" #include "hardware_ini.h" #include "flash.h" +#include "stepper_motors.h" +#include "powerhw.h" +#include "AD7794.h" // mode: curmode_t mode = BYTE_MODE; // text protocol, activated on 1st meeteng of '[' @@ -57,7 +60,7 @@ static intfun I = NULL; // function to process entered integer void print_ad_vals(sendfun s){ int j; if(ad7794_on){ - for(j = 0; j < TRD_NO; j++){ + for(j = 0; j < TRD_NO; ++j){ if(mode == LINE_MODE){ P("[ " STR_EXTADC_VALUES " ", s); print_int(j, s); @@ -92,6 +95,22 @@ void print_int_ad_vals(sendfun s){ else if(mode == LINE_MODE) P(" ]\n", s); } + if(OW_scan){ // print 1-wire temperatures + for(j = 0; j < OW_dev_amount; ++j){ + if(OW_temperature[j] != ERR_TEMP_VAL){ + if(mode == LINE_MODE) + P("[ " STR_INTADC_VALUES " ", s); + else + s('N'); + print_int(j + TRD_NO, s); + s(' '); + print_int(OW_temperature[j], s); + if(mode == LINE_MODE) + P(" ]\n", s); + else s(' '); + } + } + } } /* @@ -225,10 +244,10 @@ void help(sendfun s){ pr("L\tmove filters (2) wheel to Nth position"); pr("M\tswitch on/off ADC monitoring"); //pr("N"); - //pr("O"); - pr("P\ttest (ow_fill_id)"); - //pr("Q"); - //pr("R"); + pr("O\tturn on 1-wire scan"); + pr("P\tadd 1-wire sensor"); + pr("Q\tturn off 1-wire scan"); + pr("R\terase 1-wire IDs from memory"); pr("S\tturn AD7794 to single conversion mode"); pr(STR_PRINT_TIME "\tprint current value of time counters"); //pr("U\t(reserved)"); @@ -242,7 +261,7 @@ void help(sendfun s){ pr("c\tclose shutter"); pr("d\tchange value of ADC divisor No N"); //pr("e"); - pr("f\tsave current values of ADC mult/div to flash"); + pr("f\tupdate flash settings"); pr("g\tchange AD7794 gain"); pr(STR_SHTR_VOLTAGE "\tshow shutter voltage"); pr(STR_EXTADC_INIT "\tinit AD7794"); @@ -431,6 +450,12 @@ int parce_incoming_buf(char *buf, int len, sendfun s){ case 'o': // open shutter do_echo = try_to_open_shutter(); break; + case 'O': // 1-wire scan ON + if(!OW_scan){ + OW_scan = 1; + OW_send_read_seq(); + } + break; case CMD_MOTORS_VOLTAGE: // [p] show motors voltage * 100 if(mode == LINE_MODE) P("[ " STR_MOTORS_VOLTAGE " ", s); print_int(power_voltage(), s); @@ -438,10 +463,16 @@ int parce_incoming_buf(char *buf, int len, sendfun s){ newline(s); do_echo = 0; break; - case 'P': // (only for byte mode) + case 'P': // (only for byte mode) - add 1-wire device if(mode != BYTE_MODE) return 0; - OW_fill_ID(0); - //run_dmatimer(); + OW_fill_next_ID(); + break; + case 'Q': // 1-wire scan OFF + OW_scan = 0; + break; + case 'R': // (only for byte mode) - reset 1-wire IDs in RAM + if(mode != BYTE_MODE) return 0; + OW_dev_amount = 0; break; case 'r': // reinit shutter shutter_init(); @@ -477,14 +508,6 @@ int parce_incoming_buf(char *buf, int len, sendfun s){ /* case 'U': // test: init USART1 UART_init(USART1); break; */ - /* case 'W': // scan for one 1-wire device - if(1 == OW_Scan(onewire_addr, 1)){ - P("found 1-wire: ", s); - print_hex(onewire_addr, 8, s); - }else - P("1-wire error",s ); - P("\n", s); - break;*/ case 'x': // set period of TIM1 (motors 1..3) active_motor = 1; I = set_timr; diff --git a/with_opencm3/user_proto.h b/with_opencm3/user_proto.h index 11f7216..9756495 100644 --- a/with_opencm3/user_proto.h +++ b/with_opencm3/user_proto.h @@ -28,9 +28,10 @@ // shorthand for prnt #define P(arg, s) prnt((uint8_t*)arg, s) +#define LP(arg) prnt((uint8_t*)arg, lastsendfun) // debug message - over USB #ifdef EBUG - #define DBG(a) do{if(mode == BYTE_MODE) prnt((uint8_t*)a, usb_send);}while(0) + #define DBG(a) do{if(mode == BYTE_MODE) prnt((uint8_t*)a, lastsendfun);}while(0) #else #define DBG(a) #endif