--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/AppliSlave_HCS12/appli.c Wed May 10 16:59:40 2006 +0200
@@ -0,0 +1,514 @@
+/*
+This file is part of CanFestival, a library implementing CanOpen Stack.
+
+Copyright (C): Edouard TISSERANT and Francis DUPIN
+
+See COPYING file for copyrights details.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <stddef.h> /* for NULL */
+
+#include <asm-m68hc12/portsaccess.h>
+#include <asm-m68hc12/ports_def.h>
+#include <asm-m68hc12/ports.h>
+#include <interrupt.h>
+
+#include <applicfg.h>
+#include <candriver.h>
+#include <timerhw.h>
+
+#include "../include/def.h"
+#include "../include/can.h"
+#include "../include/objdictdef.h"
+#include "../include/objacces.h"
+#include "../include/canOpenDriver.h"
+#include "../include/sdo.h"
+#include "../include/pdo.h"
+#include "../include/init.h"
+#include "../include/timer.h"
+#include "../include/lifegrd.h"
+#include "../include/sync.h"
+
+#include "../include/nmtSlave.h"
+
+
+
+// HCS12 configuration
+// -----------------------------------------------------
+
+enum E_CanBaudrate
+{
+ CAN_BAUDRATE_250K,
+ CAN_BAUDRATE_500K,
+ CAN_BAUDRATE_1M,
+ CAN_BAUDRATE_OLD_VALUE
+};
+
+const canBusTime CAN_Baudrates[] =
+{
+ {
+ 1, /* clksrc: Use the bus clock : 16 MHz, the freq. of the quartz's board */
+ 3, /* brp : chose btw 0 and 63 (6 bits). freq time quantum = 16MHz / (brp + 1) */
+ 0, /* sjw : chose btw 0 and 3 (2 bits). Sync on (sjw + 1 ) time quantum */
+ 0, /* samp : chose btw 0 and 3 (2 bits) (samp + 1 ) samples per bit */
+ 1, /* tseg2 : chose btw 0 and 7 (3 bits) Segment 2 width = (tseg2 + 1) tq */
+ 12, /* tseg1 : chose btw 0 and 15 (4 bits) Segment 1 width = (tseg1 + 1) tq */
+
+ /*
+ With these values,
+ - The width of the bit time is 16 time quantum :
+ - 1 tq for the SYNC segment (could not be modified)
+ - 13 tq for the TIME 1 segment (tseg1 = 12)
+ - 2 tq for the TIME 2 segment (tseg2 = 1)
+ - Because the bus clock of the MSCAN is 16 MHZ, and the
+ freq of the time quantum is 4 MHZ (brp = 3+1), and there are 16 tq in the bit time,
+ so the freq of the bit time is 250 kHz.
+ */
+ },
+
+ {
+ 1, /* clksrc: Use the bus clock : 16 MHz, the freq. of the quartz's board */
+ 1, /* brp : chose btw 0 and 63 (6 bits). freq time quantum = 16MHz / (brp + 1) */
+ 0, /* sjw : chose btw 0 and 3 (2 bits). Sync on (sjw + 1 ) time quantum */
+ 0, /* samp : chose btw 0 and 3 (2 bits) (samp + 1 ) samples per bit */
+ 1, /* tseg2 : chose btw 0 and 7 (3 bits) Segment 2 width = (tseg2 + 1) tq */
+ 12, /* tseg1 : chose btw 0 and 15 (4 bits) Segment 1 width = (tseg1 + 1) tq */
+
+ /*
+ With these values,
+ - The width of the bit time is 16 time quantum :
+ - 1 tq for the SYNC segment (could not be modified)
+ - 13 tq for the TIME 1 segment (tseg1 = 12)
+ - 2 tq for the TIME 2 segment (tseg2 = 1)
+ - Because the bus clock of the MSCAN is 16 MHZ, and the
+ freq of the time quantum is 8 MHZ (brp = 1+1), and there are 16 tq in the bit time,
+ so the freq of the bit time is 500 kHz.
+ */
+ },
+
+ {
+ 1, /* clksrc: Use the bus clock : 16 MHz, the freq. of the quartz's board */
+ 1, /* brp : chose btw 0 and 63 (6 bits). freq time quantum = 16MHz / (brp + 1) */
+ 0, /* sjw : chose btw 0 and 3 (2 bits). Sync on (sjw + 1 ) time quantum */
+ 0, /* samp : chose btw 0 and 3 (2 bits) (samp + 1 ) samples per bit */
+ 1, /* tseg2 : chose btw 0 and 7 (3 bits) Segment 2 width = (tseg2 + 1) tq */
+ 4, /* tseg1 : chose btw 0 and 15 (4 bits) Segment 1 width = (tseg1 + 1) tq */
+
+ /*
+ With these values,
+ - The width of the bit time is 16 time quantum :
+ - 1 tq for the SYNC segment (could not be modified)
+ - 5 tq for the TIME 1 segment (tseg1 = 4)
+ - 2 tq for the TIME 2 segment (tseg2 = 1)
+ - Because the bus clock of the MSCAN is 16 MHZ, and the
+ freq of the time quantum is 8 MHZ (brp = 1+1), and there are 8 tq in the bit time,
+ so the freq of the bit time is 1 MHz.
+ */
+ },
+
+ {
+ 1, /* clksrc: Use the bus clock : 16 MHz, the freq. of the quartz's board */
+ 0, /* brp : chose btw 0 and 63 (6 bits). freq time quantum = 16MHz / (brp + 1) */
+ 1, /* sjw : chose btw 0 and 3 (2 bits). Sync on (sjw + 1 ) time quantum */
+ 1, /* samp : chose btw 0 and 3 (2 bits) (samp + 1 ) samples per bit */
+ 4, /* tseg2 : chose btw 0 and 7 (3 bits) Segment 2 width = (tseg2 + 1) tq */
+ 9, /* tseg1 : chose btw 0 and 15 (4 bits) Segment 1 width = (tseg1 + 1) tq */
+
+ /*
+ With these values,
+ - The width of the bit time is 16 time quantum :
+ - 1 tq for the SYNC segment (could not be modified)
+ - 10 tq for the TIME 1 segment (tseg1 = 9)
+ - 5 tq for the TIME 2 segment (tseg2 = 4)
+ - Because the bus clock of the MSCAN is 16 MHZ, and the
+ freq of the time quantum is 16 MHZ (brp = 0), and there are 16 tq in the bit time,
+ so the freq of the bit time is 1 MHz.
+ */
+ }
+};
+
+
+// The variables sent or updated by PDO
+// -----------------------------------------------------
+extern UNS8 seconds; // Mapped at index 0x2000, subindex 0x1
+extern UNS8 minutes; // Mapped at index 0x2000, subindex 0x2
+extern UNS8 hours; // Mapped at index 0x2000, subindex 0x3
+extern UNS8 day; // Mapped at index 0x2000, subindex 0x4
+extern UNS32 canopenErrNB; // Mapped at index 0x6000, subindex 0x0
+extern UNS32 canopenErrVAL; // Mapped at index 0x6001, subindex 0x0
+
+// Required definition variables
+// -----------------------------
+// The variables that you should define for debugging.
+// They are used by the macro MSG_ERR and MSG_WAR in applicfg.h
+// if the node is a slave, they can be mapped in the object dictionnary.
+// if not null, allow the printing of message to the console
+// Could be managed by PDO
+UNS8 printMsgErrToConsole = 1;
+UNS8 printMsgWarToConsole = 1;
+
+
+
+/*************************User's variables declaration**************************/
+UNS8 softCount = 0;
+UNS8 lastMinute = 0;
+UNS8 lastSecond = 0;
+UNS8 sendingError = 0;
+//--------------------------------FONCTIONS-------------------------------------
+/* You *must* have these 2 functions in your code*/
+void heartbeatError(UNS8 heartbeatID);
+void SD0timeoutError(UNS8 bus_id, UNS8 line);
+
+// Interruption timer 3. (The timer 4 is used by CanOpen)
+void __attribute__((interrupt)) timer3Hdl (void);
+
+void incDate(void);
+void initLeds(void);
+void initTimerClk(void);
+void initCanHCS12 (void);
+void initialisation(void);
+void preOperational(void);
+void operational(void);
+void stopped(void);
+//------------------------------------------------------------------------------
+
+
+//------------------------------------------------------------------------------
+// Interruption timer 3
+void __attribute__((interrupt)) timer3Hdl (void)
+{
+ //IO_PORTS_8(PORTB) ^= 0x10;
+ //IO_PORTS_8(PORTB) &= ~0x20;
+ IO_PORTS_8(TFLG1) = 0x08; // RAZ du flag interruption timer 3
+ // Calcul evt suivant. Clock 8 MHz -> 8000 evt de 1 ms!! Doit tenir sur 16 bits
+ // Attention, ça change si on utilise la pll
+ // Lorsque le timer atteindra la valeur de TC3 (16 bits), l'interruption timer3Hdl sera déclenchée
+ // Si on utilise la PLL à 24 MHZ, alors la vitesse du bus est multipliée par 3.
+
+/* Assume that our board uses a 16 MHz quartz */
+/* Without pre-division, 8000 counts takes 1 ms. */
+/* We are using a pre-divisor of 32. (register TSCR2) See in CanOpenDriverHC12/timerhw.c */
+/* So 10000 counts takes 40 ms. */
+/* We must have a soft counter of 25 to count a second. */
+
+ IO_PORTS_16(TC3H) += (10000); // IT every 40000 count.
+ softCount++;
+ if (softCount == 25) {
+ softCount = 0;
+ incDate();
+ }
+}
+
+//------------------------------------------------------------------------------
+void heartbeatError(UNS8 heartbeatID)
+{
+ MSG_ERR(0x1F00, "!!! No heart beat received from node : ", heartbeatID);
+}
+
+//------------------------------------------------------------------------------
+void SD0timeoutError (UNS8 bus_id, UNS8 line)
+{
+ // Informations on what occurs are in transfers[bus_id][line]....
+ // See scanSDOtimeout() in sdo.c
+}
+
+//------------------------------------------------------------------------------
+// Incrementation of the date, every second
+void incDate(void)
+{
+ if (seconds == 59) {
+ seconds = 0;
+ if (minutes == 59) {
+ minutes = 0;
+ if (hours == 23) {
+ hours = 0;
+ day++;
+ }
+ else
+ hours++;
+ }
+ else
+ minutes++;
+ }
+ else
+ seconds++;
+
+ // Toggle the led 4 every seconds
+ IO_PORTS_8(PORTB) ^= 0x10;
+
+}
+
+//Initialisation of the port B for the leds.
+void initLeds(void)
+{
+ // Port B is output
+ IO_PORTS_8(DDRB)= 0XFF;
+ // RAZ
+ IO_PORTS_8(PORTB) = 0xFF;
+}
+
+
+
+//------------------------------------------------------------------------------
+// Init the timer for the clock demo
+void initTimerClk(void)
+{
+
+ lock(); // Inhibe les interruptions
+
+ // Configuration du Channel 3
+ IO_PORTS_8(TIOS) |= 0x08; // Canal 3 en sortie
+ IO_PORTS_8(TCTL2) &= ~(0xC0); // Canal 3 déconnecté du pin de sortie
+ IO_PORTS_8(TIE) |= 0x08; // Autorise interruption Canal 3
+ IO_PORTS_8(TSCR1) |= 0x80; // Mise en route du timer
+ unlock(); // Autorise les interruptions
+}
+
+
+//------------------------------------------------------------------------------
+
+// A placer avant initTimer de la bibliothèque CanOpen
+/* void initTimerbis(void) */
+/* { */
+
+/* lock(); // Inhibe les interruptions */
+/* // Configuration des IT Channels (0..3) */
+/* IO_PORTS_8(TIOS) &= 0xF0; // Canals 0->3 en entrées. */
+/* IO_PORTS_8(TCTL4) &= 0XFD; // Canal 0 détection sur front montant. */
+/* IO_PORTS_8(TCTL4) |= 0X01; */
+/* IO_PORTS_8(TCTL4) &= 0XF7; // Canal 1 détection sur front montant. */
+/* IO_PORTS_8(TCTL4) |= 0X04; */
+/* IO_PORTS_8(TCTL4) &= 0XDF; // Canal 2 détection sur front montant. */
+/* IO_PORTS_8(TCTL4) |= 0X10; */
+/* IO_PORTS_8(TCTL4) &= 0X7F; // Canal 3 détection sur front montant. */
+/* IO_PORTS_8(TCTL4) |= 0X40; */
+/* IO_PORTS_8(TSCR2) |= 0X05; // Pre-scaler = 32. */
+
+/* IO_PORTS_8(ICOVW) |= 0x0F; // La sauvgrade des valeures de TC0 et TC0H */
+/* // correspondant aux canals (0..3) jusqu'a la */
+/* // prochaine lecture dans ces registres. */
+/* MASK = IO_PORTS_8(ICSYS); */
+/* MASK &= 0xFE; // Canals (0..3) en IC QUEUE MODE. */
+/* MASK |= 0x08; // Canals (0..3) : génére une interruption aprés */
+/* // la capture de deux valeures du timer sur detection */
+/* // d'un front montant à l'entrée des canals (0..3). */
+/* MASK |= 0x02; */
+/* IO_PORTS_8(ICSYS) = MASK; */
+/* IO_PORTS_16(TC0HH); // Vider le registre holding correspondant au canal0. */
+/* IO_PORTS_8(TSCR1) |= 0x10; // RAZ automatique des flags d'interruption aprés lecture */
+/* // dans les registres correspondant. */
+
+/* IO_PORTS_8(TIE) |= 0x0F; // Autorise interruption Canals (0..3). */
+/* IO_PORTS_8(TSCR2) |= 0X80; // Autorise interruption sur l'Overflow. */
+/* unlock(); // Autorise les interruptions */
+
+/* } */
+
+//------------------------------------------------------------------------------
+
+
+
+void initCanHCS12 (void)
+{
+ //Init the HCS12 microcontroler for CanOpen
+ initHCS12();
+ // Init the HCS12 CAN driver
+ const canBusInit bi0 = {
+ 0, /* no low power */
+ 0, /* no time stamp */
+ 1, /* enable MSCAN */
+ 0, /* clock source : oscillator (In fact, it is not used) */
+ 0, /* no loop back */
+ 0, /* no listen only */
+ 0, /* no low pass filter for wk up */
+ CAN_Baudrates[CAN_BAUDRATE_250K],
+ {
+ 0x00, /* Filter on 16 bits. See Motorola Block Guide V02.14 fig 4-3 */
+ 0x00, 0xFF, /* filter 0 hight accept all msg */
+ 0x00, 0xFF, /* filter 0 low accept all msg */
+ 0x00, 0xFF, /* filter 1 hight filter all of msg */
+ 0x00, 0xFF, /* filter 1 low filter all of msg */
+ 0x00, 0xFF, /* filter 2 hight filter most of msg */
+ 0x00, 0xFF, /* filter 2 low filter most of msg */
+ 0x00, 0xFF, /* filter 3 hight filter most of msg */
+ 0x00, 0xFF, /* filter 3 low filter most of msg */
+ }
+ };
+
+ canInit(CANOPEN_LINE_NUMBER_USED, bi0); //initialize filters...
+ unlock(); // Allow interruptions
+}
+
+
+/*********************************************************************/
+void initialisation( void )
+{
+ //initcapteur(); //initialisation du capteur, timer, compteurs logiciels
+ initCanHCS12(); //initialisation du bus Can
+ MSG_WAR(0X3F05, "I am in INITIALISATION mode ", 0);
+ /* Defining the node Id */
+ setNodeId(0x05);
+ MSG_WAR(0x3F06, "My node ID is : ", getNodeId());
+ {
+ UNS8 *data;
+ UNS8 size;
+ UNS8 dataType;
+ // Manufacturer Device name (default = empty string)
+ getODentry(0x1008, 0x0, (void **)&data, &size, &dataType, 0);
+ MSG_WAR(0x3F09, data, 0);
+ // Manufacturer Hardware version. (default = compilation. date)
+ getODentry(0x1009, 0x0, (void **)&data, &size, &dataType, 0);
+ MSG_WAR(0x3F09, data, 0);
+ // Manufacturer Software version. (default = compilation. time)
+ getODentry(0x100A, 0x0, (void **)&data, &size, &dataType, 0);
+ MSG_WAR(0x3F09, data, 0);
+ }
+ initCANopenMain(); //initialisation du canopen
+ heartbeatInit(); //initialisation du lifeguarding
+ initResetMode();
+ initTimer(); //initialisation of the timer used by Canopen
+ initTimerClk();
+}
+
+
+/*********************************************************************/
+void preOperational(void)
+{
+ // Test if the heartBeat have been received. Send headbeat
+ heartbeatMGR();
+ // Read message
+ receiveMsgHandler(0);
+}
+
+
+/********************************************************************/
+void operational( void )
+{
+
+ // Init the errors
+ canopenErrNB = 0;
+ canopenErrVAL = 0;
+
+ // Test if the heartBeat have been received. Send headbeat
+ heartbeatMGR();
+ // Read message
+ receiveMsgHandler(0);
+
+ if (lastMinute != minutes) {
+ MSG_WAR(0x3F00, "event : minutes change -> node decides to send it. Value : ", minutes);
+ sendPDOevent( 0, &minutes );
+ lastMinute = minutes;
+ }
+
+ if (canopenErrNB == 0)
+ sendingError = 0;
+
+
+ if (lastSecond != seconds) {
+ MSG_WAR (0x3F50, "Seconds = ", seconds);
+ if ((seconds == 50) && (sendingError == 0))
+ {
+ MSG_ERR(0x1F55, "DEMO of ERROR. Sent by PDO. Value : ", 0xABCD);
+ sendingError = 1;
+ }
+
+ if (canopenErrNB) {
+ MSG_WAR(0x3F56, "ERROR nb : ", canopenErrNB);
+ }
+ lastSecond = seconds;
+
+ }
+
+}
+
+
+/*****************************************************************************/
+void stopped( void )
+{
+ heartbeatMGR();
+ // Read message
+ receiveMsgHandler(0);
+}
+
+
+/*****************************************************************************/
+
+
+
+/********************************* MAIN ***************************************/
+
+
+int main ()
+{
+ e_nodeState lastState = Unknown_state;
+
+ /* CanOpen slave state machine */
+ /* ------------------------------------*/
+
+ while(1) { /* slave's state machine */
+
+ switch( getState() ) {
+ case Initialisation:
+ if (lastState != getState()) {
+ initLeds();
+ IO_PORTS_8(PORTB) &= ~ 0x01; // led 0 : ON
+ IO_PORTS_8(PORTB) |= 0x0E; // leds 1, 2, 3 : OFF
+ MSG_WAR(0X3F10, "Entering in INITIALISATION mode ", 0);
+ }
+ initialisation();
+ /* change automatically into pre_operational state */
+ lastState = Initialisation;
+ setState(Pre_operational);
+ break;
+
+ case Pre_operational:
+ if (lastState != getState()) {
+ IO_PORTS_8(PORTB) &= ~ 0x03; // leds 0, 1 : ON
+ IO_PORTS_8(PORTB) |= 0x0C; // leds 2, 3 : OFF
+ MSG_WAR(0X3F11, "Entering in PRE_OPERATIONAL mode ", 0);
+ initPreOperationalMode();
+ }
+ preOperational();
+ if (lastState == Initialisation)
+ slaveSendBootUp(0);
+ lastState = Pre_operational;
+ break;
+
+ case Operational:
+ if (lastState != getState()) {
+ IO_PORTS_8(PORTB) &= ~ 0x07; // leds 0, 1, 2 : ON
+ IO_PORTS_8(PORTB) |= 0x08; // leds 3 : OFF
+ MSG_WAR(0X3F12, "Entering in OPERATIONAL mode ", 0);
+ }
+ operational();
+ lastState = Operational;
+ break;
+
+ case Stopped:
+ if (lastState != getState()) {
+ IO_PORTS_8(PORTB) |= 0x0F; // leds 0, 1, 2, 3 : OFF
+ MSG_WAR(0X3F13, "Entering in STOPPED mode", 0);
+ }
+ stopped();
+ lastState = Stopped;
+ break;
+ }//end switch case
+
+ }
+ return (0);
+}
+