Buscar este blog

martes, 18 de noviembre de 2014

PRACTICA # 11 CAN ( Controller Area Network)

  • Introducción.

CAN (acrónimo del inglés Controller Area Network) es un protocolo de comunicaciones desarrollado por la firma alemana Robert Bosch GmbH, basado en una topología bus para la transmisión de mensajes en entornos distribuidos. Además ofrece una solución a la gestión de la comunicación entre múltiples CPUs (unidades centrales de proceso).
El protocolo de comunicaciones CAN proporciona los siguientes beneficios:

·         Es un protocolo de comunicaciones normalizado, con lo que se simplifica y economiza la tarea de comunicar subsistemas de diferentes fabricantes sobre una red común o bus.
·         El procesador anfitrión (host) delega la carga de comunicaciones a un periférico inteligente, por lo tanto el procesador anfitrión dispone de mayor tiempo para ejecutar sus propias tareas.
·         Al ser una red multiplexada, reduce considerablemente el cableado y elimina las conexiones punto a punto, excepto en los enganches.

CAN se basa en el modelo productor/consumidor, el cual es un concepto, o paradigma de comunicaciones de datos, que describe una relación entre un productor y uno o más consumidores. CAN es un protocolo orientado a mensajes, es decir la información que se va a intercambiar se descompone en mensajes, a los cuales se les asigna un identificador y se encapsulan en tramas para su transmisión. Cada mensaje tiene un identificador único dentro de la red, con el cual los nodos deciden aceptar o no dicho mensaje. Dentro de sus principales características se encuentran:

·         Prioridad de mensajes.
·         Garantía de tiempos de latencia.
·         Flexibilidad en la configuración.
·         Recepción por multidifusión (multicast) con sincronización de tiempos.
·         Sistema robusto en cuanto a consistencia de datos.
·         Sistema multimaestro.
·         Detección y señalización de errores.
·         Retransmisión automática de tramas erróneas
·         Distinción entre errores temporales y fallas permanentes de los nodos de la red, y desconexión autónoma de nodos defectuosos.

  • CAN fue desarrollado, inicialmente para aplicaciones en los automóviles y por lo tanto la plataforma del protocolo es resultado de las necesidades existentes en el área de la automoción. La Organización Internacional para la Estandarización (ISO, International Organization for Standarization) define dos tipos de redes CAN: una red de alta velocidad (hasta 1 Mbit/s), bajo el estándar ISO 11898-2, destinada para controlar el motor e interconectar las unidades de control electrónico (ECU); y una red de baja velocidad tolerante a fallos (menor o igual a 125 kbit/s), bajo el estándar ISO 11519-2/ISO 11898-3, dedicada a la comunicación de los dispositivos electrónicos internos de un automóvil como son control de puertas, techo corredizo, luces y asientos.


  • FRAME DE DATOS PROTOCOLO CAN.


  • METODOLOGIA.

Para poder implementar correctamente el protocolo CAN en la tecnología ZYNQ-7000 es necesario primeramente crear una red de nodos con microcontroladores.

La red de nodos propuesta se muestra en la siguiente imagen:

UN NODO

DOS NODOS

  • Es necesario por lo menos crear 2 nodos A y B con sistema de transmisión a 40 Kbps.
  • El nodo A tiene un identificador ID = 24 y enviara 8 Bytes de prueba = [AN0, Cnt, 140, 30, 168, 255, 10, 15]. Donde AN0 es el valor de un canal analógico (potenciometro) del microcontrolador PIC18F248 y Cnt es una variable de 8 bits que incrementa cada segundo su valor.

A su vez envía por medio del UART dichos valores a una hyperterminal.

El nodo B escucha los mensajes del nodo A e informa el estado de la red imprimiendo los valores en el LCD y enviando de igual manera vía UART los datos a otra hypeterminal.

  • NODO A:

while(TRUE)
   {
      //every two seconds, send new data if transmit buffer is empty
      if ( can_tbe() && (ms > 1000))
      {
         ms=0;
         out_data[0] =Read_ADC();
         out_data[1] =z++;
         //output_toggle(PIN_B5);
        // printf(LCD_PUTC,"\f  CAN v2.0 Test ");
        // printf(LCD_PUTC,"\n AN = %u", AN0);
         for (i=0;i<tx_len;i++)
         {
             printf("%u ",out_data[i]);
         }
          printf("\r\n");
         i=can_putd(tx_id, out_data, tx_len,tx_pri,tx_ext,tx_rtr); //put data on transmit buffer
      }
   }
  • NODO B:

while(TRUE)
  {
      if (can_kbhit())   //if data is waiting in buffer...
      {
         if(can_getd(rx_id, &in_data[0], rx_len, rxstat))
         { //...then get data from buffer
            printf("\r\nGOT: BUFF=%U ID=%LU LEN=%U OVF=%U ", rxstat.buffer, rx_id, rx_len, rxstat.err_ovfl);
            printf("FILT=%U RTR=%U EXT=%U INV=%U", rxstat.filthit, rxstat.rtr, rxstat.ext, rxstat.inv);
            printf("\r\n    DATA = ");
            for (i=0;i<rx_len;i++)
            {
               printf("%u ",in_data[i]);
            }
            printf(LCD_PUTC,"\fID = %Ld, LEN = %d", rx_id, rx_len);
            printf(LCD_PUTC,"\n%u %u %u %u %u",in_data[0],in_data[1],in_data[2],in_data[3],in_data[4]);
           
            printf("\r\n");
         }
         else
         {
             printf("\r\nFAIL on GETD\r\n");
             printf(LCD_PUTC,"\fFAIL on GETD");
         }
      }
}

Nodo A                                Nodo B


Nodo_A.hex

Nodo_B.hex

  • NODO A Y B COMUNICANDOSE CORRECTAMENTE!



  • Toda la información de implementación CAN sobre microcontroladores microchip la puedes encontrar en el siguiente link:

http://www.todopic.com.ar/foros/index.php?topic=19182.0



  • CONECTANDO ZEDBOARD A LA RED CAN
La librería CAN para zynq esta configurada para enviar y recibir a 40 kbps y tiene un ID = 69. Una vez programado se conectara a la red CAN como NODO C.

Conexión  SN65HVD233 (CAN PHY) con ZedBoard:



CANTXA à MIO 11
CANRXA
à MIO 10


  • Diagrama de bloques en vivado:



  • Configuración de periféricos en Zynq:


  • Configuración de reloj en Zynq:


  • SOFTWARE EN SDK:

/*

 * CONEXION sn65hvd233

 * PIN 1 --> JE3 TX (PMOD)
 * PIN 2 --> GND
 * PIN 3 --> 3.3v
 * PIN 4 --> JE2 RX (PMOD)
 * PIN 5 --> GND
 * PIN 6 --> PIN 6 MCP2551
 * PIN 7 --> PIN 7 MCP2551
 * PIN 8 --> GND
 */

/***************************** Include Files *********************************/
#include <stdio.h>
#include "xcanps.h"
#include "xparameters.h"
#include "xgpio.h"
#include "xil_printf.h"

/************************** Constant Definitions *****************************/

/*
 * The following constants map to the XPAR parameters created in the
 * xparameters.h file. They are defined here such that a user can easily
 * change all the needed parameters in one place.
 */
#define CAN_DEVICE_ID   XPAR_XCANPS_0_DEVICE_ID
#define GPIO_EXAMPLE_DEVICE_ID  XPAR_AXI_GPIO_0_DEVICE_ID
#define LED_CHANNEL 1
/*
 * Maximum CAN frame length in words.
 */
#define XCANPS_MAX_FRAME_SIZE_IN_WORDS (XCANPS_MAX_FRAME_SIZE / sizeof(u32))

#define FRAME_DATA_LENGTH                       8  /* Frame Data field length */

/*
 * Message Id Constant.
 */
#define TEST_MESSAGE_ID                         69

/*
 * The Baud Rate Prescaler Register (BRPR) and Bit Timing Register (BTR)
 * are setup such that CAN baud rate equals 40Kbps, assuming that the
 * the CAN clock is 24MHz. The user needs to modify these values based on
 * the desired baud rate and the CAN clock frequency. For more information
 * see the CAN 2.0A, CAN 2.0B, ISO 11898-1 specifications.
 */
/*
 * Timing parameters to be set in the Bit Timing Register (BTR).
 * These values are for a 40 Kbps baudrate assuming the CAN input clock
 frequency
 * is 24 MHz.
 */
#define TEST_BTR_SYNCJUMPWIDTH                  3
#define TEST_BTR_SECOND_TIMESEGMENT 2
#define TEST_BTR_FIRST_TIMESEGMENT  15

/*
 * The Baud rate Prescalar value in the Baud Rate Prescaler Register (BRPR)
 * needs to be set based on the input clock  frequency to the CAN core and
 * the desired CAN baud rate.
 * This value is for a 40 Kbps baudrate assuming the CAN input clock frequency
 * is 24 MHz.
 */
#define TEST_BRPR_BAUD_PRESCALAR    29

/**************************** Type Definitions *******************************/

/***************** Macros (Inline Functions) Definitions *********************/

/************************** Function Prototypes ******************************/

int CanPsPolledExample(u16 DeviceId);
static int SendFrame(XCanPs *InstancePtr);
static int RecvFrame(XCanPs *InstancePtr);

/************************** Variable Definitions *****************************/

/*
 * Buffers to hold frames to send and receive. These are declared as global so
 * that they are not on the stack.
 * These buffers need to be 32-bit aligned
 */
static u32 TxFrame[XCANPS_MAX_FRAME_SIZE_IN_WORDS]; //4
static u32 RxFrame[XCANPS_MAX_FRAME_SIZE_IN_WORDS]; //4

/* Driver instance */
static XCanPs Can;
XGpio Gpio;        // The Instance of the GPIO Driver

/****************************************************************************/
/**
*
* This function is the main function of the Can polled example.
*
* @param    None
*
* @return
*                       - XST_SUCCESS if the example has completed successfully.
*                       - XST_FAILURE if the example has failed.
*
* @note                 None
*
*****************************************************************************/
long int ust_limit = 83333323;
long int delay;

#ifndef TESTAPP_GEN
int main()
{
            int Status;

            // Initialize the GPIO driver

            Status = XGpio_Initialize(&Gpio, GPIO_EXAMPLE_DEVICE_ID);
            if (Status != XST_SUCCESS) {
                 return XST_FAILURE;
             }

            // Clear the LEDs
            XGpio_DiscreteWrite(&Gpio, LED_CHANNEL, 0);

            xil_printf(Microcarsil, 2014\n");
            xil_printf("CAN Polled Mode Example Test \r\n");

            /*
             * Run the Can Polled example, specify the Device ID that is generated
             * in xparameters.h .
             */
            Status = CanPsPolledExample(CAN_DEVICE_ID);
            if (Status != XST_SUCCESS) {
                        xil_printf("CAN Polled Mode Example Test Failed\r\n");
                        return XST_FAILURE;
            }

            xil_printf("\nSuccessfully ran CAN Polled Mode Example Test\r\n");
            return XST_SUCCESS;
}
#endif
/*****************************************************************************/
/**
*
* The entry point for showing the XCanPs driver in polled mode. The example
* configures the device for internal loop back mode, then sends a Can
* frame, receives the same Can frame, and verifies the frame contents.
*
* @param    DeviceId is the XPAR_<CANPS_instance>_DEVICE_ID value from
*                       xparameters.h
*
* @return   XST_SUCCESS if successful, otherwise driver-specific error code.
*
* @note
*
* If the device is not working correctly, this function may enter an infinite
* loop and will never return to the caller.
*
******************************************************************************/
int CanPsPolledExample(u16 DeviceId)
{
            int Status;
            XCanPs *CanInstPtr = &Can;
            XCanPs_Config *ConfigPtr;

            /*
             * Initialize the Can device.
             */
            ConfigPtr = XCanPs_LookupConfig(DeviceId);
            if (CanInstPtr == NULL) {
                        return XST_FAILURE;
            }
            Status = XCanPs_CfgInitialize(CanInstPtr,
                                                            ConfigPtr,
                                                            ConfigPtr->BaseAddr);
            if (Status != XST_SUCCESS) {
                        return XST_FAILURE;
            }

            /*
             * Run self-test on the device, which verifies basic sanity of the
             * device and the driver.
             */
            Status = XCanPs_SelfTest(CanInstPtr);
            if (Status != XST_SUCCESS) {
                        return XST_FAILURE;
            }

            /*
             * Enter Configuration Mode so we can setup Baud Rate Prescaler
             * Register (BRPR) and Bit Timing Register (BTR).
             */
            XCanPs_EnterMode(CanInstPtr, XCANPS_MODE_CONFIG);
            while(XCanPs_GetMode(CanInstPtr) != XCANPS_MODE_CONFIG);

            /*
             * Setup Baud Rate Prescaler Register (BRPR) and
             * Bit Timing Register (BTR).
             */
            XCanPs_SetBaudRatePrescaler(CanInstPtr, TEST_BRPR_BAUD_PRESCALAR);
            XCanPs_SetBitTiming(CanInstPtr, TEST_BTR_SYNCJUMPWIDTH,
                                                TEST_BTR_SECOND_TIMESEGMENT,

                                                TEST_BTR_FIRST_TIMESEGMENT);

            /*
             * Enter Loop Back Mode.
             */
            XCanPs_EnterMode(CanInstPtr, XCANPS_MODE_NORMAL); // XCANPS_MODE_LOOPBACK
            while(XCanPs_GetMode(CanInstPtr) != XCANPS_MODE_NORMAL);  // XCANPS_MODE_LOOPBACK

            /*
             * Send a frame, receive the frame via the loop back and verify its
             * contents.
             */

            Status = SendFrame(CanInstPtr);

            //Status = RecvFrame(CanInstPtr);

            return Status;
}


/*****************************************************************************/
/**
*
* Send a CAN frame.
*
* @param    InstancePtr is a pointer to the driver instance
*
* @return   XST_SUCCESS if successful, a driver-specific return code if not.
*
* @note
*
* This function waits until TX FIFO has room for at least one frame before
* sending a frame. So this function may block if the hardware is not built
* correctly.
*
******************************************************************************/
static int SendFrame(XCanPs *InstancePtr)
{
            u8 *FramePtr;
            int Index;
            int Status, i;

            /*
             * Create correct values for Identifier and Data Length Code Register.
             */
            TxFrame[0] = (u32)XCanPs_CreateIdValue(0, 1, 1, (u32)TEST_MESSAGE_ID, 0);
            TxFrame[1] = (u32)XCanPs_CreateDlcValue((u32)FRAME_DATA_LENGTH);

            /*
             * Now fill in the data field with known values so we can verify them
             * on receive.
             */
            FramePtr = (u8 *)(&TxFrame[2]);


            FramePtr[3] =  0;   //1er byte
            FramePtr[2] =  1;   //2do byte
            FramePtr[1] =  2;   //3er byte
            FramePtr[0] =  3;   //4to byte
            FramePtr[7] =  4;   //5to byte
            FramePtr[6] =  5;   //6to byte
            FramePtr[5] =  6;   //7to byte
            FramePtr[4] =  7;   //8vo byte


            /*
             * Now send the frame.
             *
             * Another way to send a frame is keep calling XCanPs_Send() until it
             * returns XST_SUCCESS. No check on if TX FIFO is full is needed anymore
             * in that case.
             */
            while (1)
                {
                        for(i=0;i<255;i++)
                        {
                                      XGpio_DiscreteWrite(&Gpio, LED_CHANNEL, i);
                                      for(delay=0;delay<ust_limit;delay++){};
                                      /*
                                                 * Wait until TX FIFO has room.
                                       */
                                      FramePtr[3] =  i;   //1er byte
                                      while (XCanPs_IsTxFifoFull(InstancePtr) == TRUE);
                                      Status = XCanPs_Send(InstancePtr, TxFrame);
                        }
                }

            return Status;
}


/*****************************************************************************/
/**
*
* This function receives a frame and verifies its contents.
*
* @param    InstancePtr is a pointer to the driver instance.
*
* @return   XST_SUCCESS if successful, a driver-specific return code if not.
*
* @note
*
* This function waits until RX FIFO becomes not empty before reading a frame
* from it. So this function may block if the hardware is not built
* correctly.
*
******************************************************************************/
static int RecvFrame(XCanPs *InstancePtr)
{
            u8 *FramePtr;
            int Status;
            int Index;
    u32 test =123;
    unsigned char i=0;

    while (1)
    {
               XGpio_DiscreteWrite(&Gpio, LED_CHANNEL, i++);
               //for(delay=0;delay<ust_limit;delay++){};
            /*
             * Wait until a frame is received.
             */
            while (XCanPs_IsRxEmpty(InstancePtr) == TRUE)
            {
                                    //printf("wait\n\r");
                                    //for(delay=0;delay<ust_limit;delay++){};

            }

            /*
             * Receive a frame and verify its contents.
             */
            Status = XCanPs_Recv(InstancePtr, RxFrame);
            if (Status == XST_SUCCESS) {
                        /*
                         * Verify Identifier and Data Length Code.
                         */
                        if (RxFrame[0] !=
                                    (u32)XCanPs_CreateIdValue((u32)TEST_MESSAGE_ID, 0, 0, 0, 0))
                                    //return XST_LOOPBACK_ERROR;

                        if ((RxFrame[1] & ~XCANPS_DLCR_TIMESTAMP_MASK) != TxFrame[1])
                                    //return XST_LOOPBACK_ERROR;

                        /*
                         * Verify Data field contents.
                         */

                        FramePtr = (u8 *)(&RxFrame[0]);
                        xil_printf(" ID =  %d  \n",FramePtr[2]);
                        xil_printf(" RxFrame[0] =  %d",FramePtr[11]);
                        xil_printf("    RxFrame[1] =  %d  \n",FramePtr[10]);
                        xil_printf(" RxFrame[2] =  %d",FramePtr[9]);
                        xil_printf("    RxFrame[3] =  %d  \n",FramePtr[8]);
                        xil_printf(" RxFrame[4] =  %d",FramePtr[15]);
                        xil_printf("    RxFrame[5] =  %d  \n",FramePtr[14]);
                        xil_printf(" RxFrame[6] =  %d",FramePtr[13]);
                        xil_printf("    RxFrame[7] =  %d  \n",FramePtr[12]);


                        for (Index = 0; Index < FRAME_DATA_LENGTH+8; Index++)
                        {
                                    //xil_printf(" %d  ",*FramePtr++);
                                    //xil_printf(" RxFrame[%d] =  %d  \n",Index,*FramePtr++);
                        }
                        xil_printf(" \r\n  ");
                        //for (Index = 0; Index < FRAME_DATA_LENGTH; Index++)
                        //{
                        //          printf(" %i  ",RxFrame[Index]);
                        //}
            }
    }

            return Status;
}

  • Entorno SDK de eclipse:


  • FUNCIONANDO!














1 comentario:

  1. Dear Sir, I would like to ask your contact information.
    Best regards
    ronnie71@naver.com

    ResponderBorrar