- 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
Conexión SN65HVD233 (CAN PHY) con ZedBoard:
- CONECTANDO ZEDBOARD A LA RED CAN
Conexión SN65HVD233 (CAN PHY) con ZedBoard:
CANTXA à MIO 11
CANRXA à MIO 10
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!
Dear Sir, I would like to ask your contact information.
ResponderBorrarBest regards
ronnie71@naver.com