diff --git a/src/led.c b/src/led.c index 3724e13..76c81e5 100644 --- a/src/led.c +++ b/src/led.c @@ -1,164 +1,201 @@ #include "led.h" #include "timer.h" #include <p33Fxxxx.h> #define NB_LEDS 4 //we set a frequency of blinking of 3 Hz #define DEFAULT_HALF_PERIOD 50/8 enum led_state { LED_OFF = 0x00, LED_ON = 0x01, LED_BLINKING = 0x02, }; typedef void(*led_write_fptr)(char); struct led_def{ enum led_state state; unsigned int ticks_per_half_period; unsigned int nb_ticks; unsigned int nb_blink; unsigned int current_nb_blinks; led_write_fptr write_fptr; }; +// WARNING xc16 if using ternary operator for manipulating LAT +// registers will not use semi-atomic BSET and BCLR, leading to race +// conditions !!! For safety of any race condition, I even disable all +// interrupt for these instructions void led_green1_write(char on){ - LATBbits.LATB15 = on == 0 ? 0 : 1; + //prevent race condition with all interrupt !!! + if(on) { + SRbits.IPL = 7; + LATBbits.LATB15 = 1; + SRbits.IPL = 0; + } else { + SRbits.IPL = 7; + LATBbits.LATB15 = 0; + SRbits.IPL = 0; + } } void led_yellow_write(char on){ - LATBbits.LATB14 = on == 0 ? 0 : 1; + if(on) { + SRbits.IPL = 7; + LATBbits.LATB14 = 1; + SRbits.IPL = 0; + } else { + SRbits.IPL = 7; + LATBbits.LATB14 = 0; + SRbits.IPL = 0; + } } void led_green2_write(char on){ - LATAbits.LATA0 = on == 0 ? 0 : 1; + if(on){ + SRbits.IPL = 7; + LATAbits.LATA0 = 1; + SRbits.IPL = 0; + } else { + SRbits.IPL = 7; + LATAbits.LATA0 = 0; + SRbits.IPL = 0; + } } void led_red_write(char on){ - LATAbits.LATA1 = on == 0 ? 0 : 1; + if(on) { + SRbits.IPL = 7; + LATAbits.LATA1 = 1; + SRbits.IPL = 0; + } else { + SRbits.IPL = 7; + LATAbits.LATA1 = 0; + SRbits.IPL = 0; + } } struct led_def leds[NB_LEDS] = { {LED_ON,DEFAULT_HALF_PERIOD,0,1,0,&led_green1_write}, {LED_OFF,DEFAULT_HALF_PERIOD,0,2,0,&led_yellow_write}, {LED_OFF,DEFAULT_HALF_PERIOD,0,4,0,&led_green2_write}, {LED_OFF,DEFAULT_HALF_PERIOD,0,1,0,&led_red_write}, }; void led_compute_and_apply_state(led_id l_id, unsigned int nb_ticks) { struct led_def * l = &(leds[l_id]); unsigned char led_should_be_on = 0; switch (l->state) { case LED_OFF : led_should_be_on = 0; break; case LED_ON: led_should_be_on = 1; break; case LED_BLINKING : { l->nb_ticks += nb_ticks; if(l->nb_ticks >= 2 * l->ticks_per_half_period ) { l->nb_ticks -= 2 * l->ticks_per_half_period; ++l->current_nb_blinks; } if(l->current_nb_blinks >= 2 * l->nb_blink - 1 ) { l->current_nb_blinks = 0; } if(l->nb_ticks < l->ticks_per_half_period) { led_should_be_on = 1; } if (l->current_nb_blinks >= l->nb_blink) { led_should_be_on = 0; } break; } default: break; } (*(l->write_fptr))(led_should_be_on); } void led_init(){ // GREEN_1 TRISBbits.TRISB14 = 0; // YELLOW TRISBbits.TRISB15 = 0; // GREEN_2 TRISAbits.TRISA0 = 0; // RED TRISAbits.TRISA1 = 0; } void led_main(){ static ticks last_frame = 0; //we increment the frame every 50ms if( ticks_since(last_frame) >= LED_FRAME_TIME ) { last_frame = current_time(); } else { //we only process each frame return; } unsigned int i = 0; for(; i < NB_LEDS ; ++ i){ led_compute_and_apply_state(i,1); } } void led_on(led_id l_id) { leds[l_id].state = LED_ON; } void led_off(led_id l_id) { leds[l_id].state = LED_OFF; } void led_toggle(led_id l_id) { leds[l_id].state = leds[l_id].state == LED_OFF ? LED_ON : LED_OFF; } void led_blink(led_id l_id) { if(leds[l_id].state == LED_BLINKING) { return; } leds[l_id].current_nb_blinks = 0; leds[l_id].nb_ticks = 0; leds[l_id].state = LED_BLINKING; } void led_blink_with_params(led_id l_id, unsigned int nb_blink) { leds[l_id].nb_blink = nb_blink; led_blink(l_id); } diff --git a/src/main.c b/src/main.c index 4a0367f..8a75718 100644 --- a/src/main.c +++ b/src/main.c @@ -1,139 +1,149 @@ /* * Copyright (C) 2011-2013 Rico Moeckel, Alexandre Tuleu */ /** * \defgroup main MAIN * \brief Main file for the project. * This is the main file. * \author Rico Moeckel, Alexandre Tuleu * \version 2.0 * \date 2013-05-14 */ /*@{*/ /** * \file main.c * \brief Main file for the project. */ #include "config.h" #include <p33Fxxxx.h> #include "timer.h" #include "uart.h" #include "led.h" #include "sbcp_host.h" #include "sbcp_bus.h" /************************************************************************* * CONFIGURATION BITS * * With MPLAB X, microchip removed the ability to configure bits from * the GUI, and asked to do it directly from the code. It seems to be * a feature and not a lack of feature. So it will be better do to it * all the time from now ! *************************************************************************/ //Disable watch dog _FWDT(WDTPOST_PS32768 & WDTPRE_PR128 & WINDIS_OFF & FWDTEN_OFF) //pic started by external clock. _FOSC(POSCMD_NONE & OSCIOFNC_ON & FCKSM_CSECMD) //external clock _FOSCSEL(FNOSC_FRC & IESO_OFF) /** * \brief Initialization function for the clock of the microcontroller * * This function configures the clock system of the microcontroller to * use the internal oscillator as well as the PLL to run the clock at * maximum speed of 40MIPS. * */ void clock_init() { // Disable Watch Dog Timer RCONbits.SWDTEN=0; // Configure PLL prescaler, PLL postscaler, PLL divisor PLLFBD = 41; // M = 43 CLKDIVbits.PLLPOST=0; // N2 = 2 CLKDIVbits.PLLPRE=0; // N1 = 2 // Initiate Clock Switch to Internal FRC with PLL (NOSC = 0b001) __builtin_write_OSCCONH(0x01); __builtin_write_OSCCONL(0x01); // Wait for Clock switch to occur while (OSCCONbits.COSC != 0b001){}; // Wait for PLL to lock while(OSCCONbits.LOCK != 1) {}; } /** \brief Main initialization function for the microcontroller This * function calls all individual initialization functions of the * submodules. Register your local init functions here. Be careful * about the correct order of initializations. This function has to be * called inside the main routine before any other funtions. * * \param no parameters * \return no returns */ void main_init() { clock_init(); ADPCFG = 0xffff; // Set all Analog ports as Digital I/O TRISA = 0xffff; // Everything is input TRISB = 0xffff; // Everything is input + //debug pins + TRISBbits.TRISB11 = 0; + _LATB11 = 0; + + timer_init(); led_init(); init_sbcp_host(); init_sbcp_bus(); } /** \brief Main function * * This function is the main function. It calls the main_init() * function and handles all main functions of the individual modules. * \param no parameters * \return int status */ int main() { main_init(); ticks oflw = rtc_overflow(); while (1) { //these line of codes ensure that our beloved interface will //not strip away our code with optimization. Do not ask why, //but its work (actually I perform some dummy operation every //overflow. if (oflw != rtc_overflow() ){ oflw = rtc_overflow(); } sbcp_process_host_tx(); sbcp_process_bus(); sbcp_process_host_rx(); - - led_main(); + SRbits.IPL = 7; + _LATB11 = 1; + SRbits.IPL = 0; + led_main(); + SRbits.IPL = 7; + _LATB11 = 0; + SRbits.IPL = 1; } return 0; } /*@}*/ diff --git a/src/timer.c b/src/timer.c index 3c501ef..fda1935 100644 --- a/src/timer.c +++ b/src/timer.c @@ -1,60 +1,60 @@ /* timer.c Copyright (C) 2013 Alexandre Tuleu <alexandre.tuleu.2005@polytechnique.org> EPFL Biorobotics Laboratory (http://biorob.epfl.ch) EPFL Ecole Polytechnique Federale de Lausanne (http://www.epfl.ch) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (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, see <http://www.gnu.org/licenses/>. */ #include "timer.h" #include <p33Fxxxx.h> volatile unsigned int rtc_overflow_; /** * Initializes just one single timer at the maximum prescaling. No * interruption, we just fill up current_time up to 0xffff and cycle * in real-time. It allows nice comparison of dates. */ void timer_init() { /* Set timer 1 as main clock */ T1CONbits.TON = 0; // Disable Timer T1CONbits.TCS = 0; // Select internal instruction cycle clock T1CONbits.TGATE = 0; // Disable Gated Timer mode PR1 = 0xffff; //cycle when completely full - T1CONbits.TCKPS = 0b11; // Select 1:8 Prescaler + T1CONbits.TCKPS = 0b11; // Select 1:256 prescaler TMR1 = 0x00; // Clear timer register - IPC0bits.T1IP = 0x01; // Set Timer1 Interrupt Priority Level to 1 = lowest priority + IPC0bits.T1IP = 0x01; // Set Timer1 Interrupt Priority Level to 1 = lowest priority IFS0bits.T1IF = 0; // Clear Timer1 Interrupt Flag IEC0bits.T1IE = 1; // clear Timer1 interrupt T1CONbits.TON = 1; // Start Timer } void __attribute__((__interrupt__, no_auto_psv)) _T1Interrupt(void) { /* Interrupt Service Routine code goes here */ IFS0bits.T1IF = 0; // Clear Timer 1 Interrupt Flag ++rtc_overflow_; } /*@}*/