www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik CAn Empfang beim LPC1768


Autor: Tom (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo alle zusammen,
ich würde gerne mit meinem LPC1768 Daten empfangen und auswerten auf dem 
CAN1, ich habe mich dazu durch das Datenblatt gearbeitet und mir das 
Beispielprogramm von NXP vorgenommen.
Leider ist mir schleierhaft was ich in meinem Hauptprogramm alles 
einstellen muss, ich hoffe hier das das jemand mal gemacht und dieser 
jemand kann mir helfen =)
Ich hab meine Schaltung an CANoe angeschlossen und sehe auch, dass die 
beiden miteinander kommunizieren sprich keine Errors, nun würde ich 
gerne eine Nachricht mit einem speziellen Identifier senden und diese 
dann auch empfangen, weiß nur nicht genau wie ich das machen soll.

Für hilfe bin ich sehr dankbar =)

Hier einmal der Code der can.c Datei auf welcher mein Programm basieren 
soll
/*****************************************************************************
 *  can.c:  CAN module API file for NXP LPC17xx Family Microprocessors
 *
 *   Copyright(C) 2009, NXP Semiconductor
 *   All rights reserved.
 *
 *   History
 *   2009.05.27  ver 1.00    Prelimnary version, first Release
 *   13.10.2010  ver 1.1     Änderung bezüglich CAN2
*****************************************************************************/
#include "lpc17xx.h"
#include "type.h"
#include "can.h"

/* Receive Queue: one queue for each CAN port */
extern CAN_MSG MsgBuf_RX1;
extern volatile uint32_t CAN1RxDone;
volatile uint32_t CANStatus;
uint32_t CAN1RxCount = 0;
uint32_t CAN1ErrCount = 0;

/******************************************************************************
** Function name:    CAN_ISR_Rx1
**
** Descriptions:    CAN Rx1 interrupt handler
**
** parameters:      None
** Returned value:    None
** 
******************************************************************************/
void CAN_ISR_Rx1( void )
{
  uint32_t * pDest;

  /* initialize destination pointer  */
  pDest = (uint32_t *)&MsgBuf_RX1;
  *pDest = LPC_CAN1->RFS;  /* Frame  */

  pDest++;
  *pDest = LPC_CAN1->RID; /* ID  */
  

  pDest++;
  *pDest = LPC_CAN1->RDA; /* Data A */


  pDest++;
  *pDest = LPC_CAN1->RDB; /* Data B  */

  
  CAN1RxDone = TRUE;
  LPC_CAN1->CMR = 0x04; /* release receive buffer */
  return;
}

/*****************************************************************************
** Function name:    CAN_Handler
**
** Descriptions:    CAN interrupt handler
**
** parameters:      None
** Returned value:    None
** 
*****************************************************************************/
void CAN_IRQHandler(void)  
{    

  CANStatus = LPC_CANCR->CANRxSR;
  if ( CANStatus & (1 << 8) )
  {
  CAN1RxCount++;
  CAN_ISR_Rx1();
  }

  if ( LPC_CAN1->GSR & (1 << 6 ) )
  {
  /* The error count includes both TX and RX */
  CAN1ErrCount = LPC_CAN1->GSR >> 16;
  }
  return;
}

/******************************************************************************
** Function name:    CAN_Init
**
** Descriptions:    Initialize CAN, install CAN interrupt handler
**
** parameters:      bitrate
** Returned value:    true or false, false if initialization failed.
** 
******************************************************************************/
uint32_t CAN_Init( uint32_t can_btr )
{
  CAN1RxDone = FALSE;

  LPC_SC->PCONP |= ((1<<13)|(1<<14));  /* Enable CAN1 and CAN2 clock */

  LPC_PINCON->PINSEL0 &= ~0x0000000F;  /* CAN1 is p0.0 and p0.1  */
  LPC_PINCON->PINSEL0 |= 0x00000005;  

  LPC_CAN1->MOD = 1;    /* Reset CAN */
  LPC_CAN1->IER = 0;    /* Disable Receive Interrupt */
  LPC_CAN1->GSR = 0;    /* Reset error counter when CANxMOD is in reset  */

  LPC_CAN1->BTR = can_btr;
  LPC_CAN1->MOD = 0x0;  /* CAN in normal operation mode */

  LPC_CAN1->IER = 0x01; /* Enable receive interrupts */
  return( TRUE );
}

/******************************************************************************
** Function name:    CAN_SetACCF_Lookup
**
** Descriptions:    Initialize CAN, install CAN interrupt handler
**
** parameters:      bitrate
** Returned value:    true or false, false if initialization failed.
** 
******************************************************************************/
void CAN_SetACCF_Lookup( void )
{
  uint32_t address = 0;
  uint32_t i;
  uint32_t ID_high, ID_low;

  /* Set explicit standard Frame */ 
  LPC_CANAF->SFF_sa = address;
  for ( i = 0; i < ACCF_IDEN_NUM; i += 2 )
  {
  ID_low = (i << 29) | (EXP_STD_ID << 16);
  ID_high = ((i+1) << 13) | (EXP_STD_ID << 0);
  *((volatile uint32_t *)(LPC_CANAF_RAM_BASE + address)) = ID_low | ID_high;
  address += 4; 
  }
    
  /* Set group standard Frame */
  LPC_CANAF->SFF_GRP_sa = address;
  for ( i = 0; i < ACCF_IDEN_NUM; i += 2 )
  {
  ID_low = (i << 29) | (GRP_STD_ID << 16);
  ID_high = ((i+1) << 13) | (GRP_STD_ID << 0);
  *((volatile uint32_t *)(LPC_CANAF_RAM_BASE + address)) = ID_low | ID_high;
  address += 4; 
  }
 
  /* Set explicit extended Frame */ 
  LPC_CANAF->EFF_sa = address;
  for ( i = 0; i < ACCF_IDEN_NUM; i++  )
  {
  ID_low = (i << 29) | (EXP_EXT_ID << 0);
  *((volatile uint32_t *)(LPC_CANAF_RAM_BASE + address)) = ID_low;
  address += 4; 
  }

  /* Set group extended Frame */
  LPC_CANAF->EFF_GRP_sa = address;
  for ( i = 0; i < ACCF_IDEN_NUM; i++  )
  {
  ID_low = (i << 29) | (GRP_EXT_ID << 0);
  *((volatile uint32_t *)(LPC_CANAF_RAM_BASE + address)) = ID_low;
  address += 4; 
  }
   
  /* Set End of Table */
  LPC_CANAF->ENDofTable = address;
  return;
}

/******************************************************************************
** Function name:    CAN_SetACCF
**
** Descriptions:    Set acceptance filter and SRAM associated with  
**
** parameters:      ACMF mode
** Returned value:    None
**
** 
******************************************************************************/
void CAN_SetACCF( uint32_t ACCFMode )
{
  switch ( ACCFMode )
  {
  case ACCF_OFF:
    LPC_CANAF->AFMR = ACCFMode;
    LPC_CAN1->MOD = LPC_CAN2->MOD = 1;  // Reset CAN
    LPC_CAN1->IER = LPC_CAN2->IER = 0;  // Disable Receive Interrupt
    LPC_CAN1->GSR = LPC_CAN2->GSR = 0;  // Reset error counter when CANxMOD is in reset
  break;

  case ACCF_BYPASS:
    LPC_CANAF->AFMR = ACCFMode;
  break;

  case ACCF_ON:
  case ACCF_FULLCAN:
    LPC_CANAF->AFMR = ACCF_OFF;
    CAN_SetACCF_Lookup();
    LPC_CANAF->AFMR = ACCFMode;
  break;

  default:
  break;
  }
  return;
}

/******************************************************************************
** Function name:    CAN1_SendMessage
**
** Descriptions:    Send message block to CAN1  
**
** parameters:      pointer to the CAN message
** Returned value:    true or false, if message buffer is available,
**            message can be sent successfully, return TRUE,
**            otherwise, return FALSE.
** 
******************************************************************************/
uint32_t CAN1_SendMessage( CAN_MSG *pTxBuf )
{
  uint32_t CANStatus;

  CANStatus = LPC_CAN1->SR;
  if ( CANStatus & 0x00000004 )
  {
  LPC_CAN1->TFI1 = pTxBuf->Frame & 0xC00F0000;
  LPC_CAN1->TID1 = pTxBuf->MsgID;
  LPC_CAN1->TDA1 = pTxBuf->DataA;
  LPC_CAN1->TDB1 = pTxBuf->DataB;
  LPC_CAN1->CMR = 0x21;
  return ( TRUE );
  }
  else if ( CANStatus & 0x00000400 )
  {
  LPC_CAN1->TFI2 = pTxBuf->Frame & 0xC00F0000;
  LPC_CAN1->TID2 = pTxBuf->MsgID;
  LPC_CAN1->TDA2 = pTxBuf->DataA;
  LPC_CAN1->TDB2 = pTxBuf->DataB;
  LPC_CAN1->CMR = 0x41;
  return ( TRUE );
  }
  else if ( CANStatus & 0x00040000 )
  {  
  LPC_CAN1->TFI3 = pTxBuf->Frame & 0xC00F0000;
  LPC_CAN1->TID3 = pTxBuf->MsgID;
  LPC_CAN1->TDA3 = pTxBuf->DataA;
  LPC_CAN1->TDB3 = pTxBuf->DataB;
  LPC_CAN1->CMR = 0x81;
  return ( TRUE );
  }
  return ( FALSE );
}

/******************************************************************************
**                            End Of File
******************************************************************************/


und hier mein main Programm wobei ich weiß das dieses mit Sicherheit so nicht korrekt ist aber deshalb brauch ich ja eure Hilfe =)

[c]

/******************************Header Dateien einbinden***********************************/
#include "lpc17xx.h"
#include "type.h"
#include "can.h"

CAN_MSG MsgBuf_TX1, MsgBuf_TX2; /* TX and RX Buffers for CAN message */
CAN_MSG MsgBuf_RX1, MsgBuf_RX2; /* TX and RX Buffers for CAN message */

volatile uint32_t CAN1RxDone = FALSE, CAN2RxDone = FALSE;


/*****************************************************************************
** Function name:    main
**
** Descriptions:    main routine for CAN module test
**
** parameters:      None
** Returned value:    int
** 
*****************************************************************************/
int main( void )
{

  SystemInit();
  INOUT_Def();
 
  /* Please note, the bit timing is based on the setting of the 
  PCLK, if different PCLK is used, please read can.h carefully 
  and set your CAN bit timing accordingly. */  
  //CAN_Init( BITRATE100K24MHZ );
  CAN_Init(BITRATE500K15MHZ);  
  NVIC_EnableIRQ(CAN_IRQn);
  CAN_SetACCF(ACCF_BYPASS);
  CAN_SetACCF_Lookup();
  while(1)
  {

    if(!(LPC_CAN1->RID & 0x23))
    {
      LPC_GPIO2->FIOPIN &= ~(0x000000FF);
    }
    
  }

}
[/c]

Autor: Lutz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mit einem Cortex M3, und dazu auch noch CAN, hast Du Dir natürlich für 
den Anfang auch gleich einen richtigen Hammer zum Üben ausgesucht.
Mit FIOPIN kannst Du einen Port lesen, aber nicht schreiben.
Und das if da drüber tut wahrscheinlich auch nicht das, was Du denkst. 
Schreibe den Inhalt des Tests einfach mal binär auf einen Zettel und 
schau, ob es das ist, was Du meinst.

Was ist denn CANoe, SystemInit() und INOUT_Def()? In der Lib finde ich 
die auf die Schnelle nicht.

Und wenn Du da schon irgendwie eine errorfreie Kommunkation mit 
hinbekommen hast, brauchst Du doch eigentlich nur im Datenblatt und der 
Lib nachschauen, wo die Filter definiert werden und diesen Teil an Deine 
Bedürfnisse anpassen.

Wie gesagt: CM3 und dazu CAN ist schon ein Hammer; ich lese mich da 
selbst gerade erst ein. Da ist soviel zu bedenken; Takte, 
Initialisierungen etc. Mit der Lib habe ich mich allerdings noch gar 
nicht beschäftigt. Vielleicht nimmt die einem ja allerhand ab, kann 
sein.

Autor: Erwin Reuss (er-tronik)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich finde es traurig, wenn Leute hier antworten, die selber nicht genau 
über das Thema Bescheid wissen. Mit FIOPIN kann sehr wohl gelesen wie 
auch geschrieben werden. Aber das wird in der Regel bei diesen 
Controllern nicht gemacht, sondern es werden die Befehle FIOSET und 
FIOCLR zum geziehlten Setzen und Löschen von IO-Pins genutzt.

Da ich mich gerade in den letzten Wochen die CAN-Communikation mit dem 
LPC1766 beschäftigt hatte, kann ich nur sagen, so schlimm ist das Ganze 
gar nicht. Der große Unterschied gegenüber vielen anderen 
CAN-Controllern ist hier der Harware-Filter, den man aber für die ersten 
Experimente gar nicht braucht. Aber wichtig, unbedingt den Filter auf 
ACCF_BYPASS setzen, sonst empfängt das Teil nämlich gar nichts.

Das Senden eines CAN-Paketes ist doch ganz einfach, du brauchst nur eine 
Struktur, die du mit allen wichtigen Daten füllst und dann einfach 
absendest:
CAN_MSG TxBuf;
int rc;

TxBuf.Frame = (8 << 16)   ; 8 Bytes,  | (1 << 31) bei 29 Bit ID
TxBuf.MsgId = 0x789       ; oder 29 Bit ID
TxBuf.DataA = 0x01234567
TxBuf.DataB = 0x89ABCDEF

rc = CAN1_SendMessage(&TxBuf);

Das wars. Alles andere sollte so klappen, wie in deinem Listing.
Wichtig ist natürlich noch, daß die Bitratenwerte mit der Taktfrequenz 
deines Controllers übereinstimmen.


Erwin

Autor: Tom (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen dank für die netten antworten =)
Das mit FIOSET und FIOCLR werd ich mir zu Herzen nehmen danke, hatte das 
bisher mit FIOPIN gemacht aber wenn es anders üblicher ist werd ich das 
umändern =)

Ich habe gestern noch ein bisschen rumprobiert und habe mir die 
LookupTable angesehen. Ich kann in CANoe sehen, dass ich bereits daten 
senden kann nur geht es mir ja noch um das Empfangen.

ich poste jetzt zur besseren strukturierung nocheinmal den Code der 
LookupTable aus der can.c
void CAN_SetACCF_Lookup( void )
{
  uint32_t address = 0;
  uint32_t i;
  uint32_t ID_high, ID_low;

  /* Set explicit standard Frame */ 
  LPC_CANAF->SFF_sa = address;
  for ( i = 0; i < ACCF_IDEN_NUM; i += 2 )
  {
  ID_low = (i << 29) | (EXP_STD_ID << 16);
  ID_high = ((i+1) << 13) | (EXP_STD_ID << 0);
  *((volatile uint32_t *)(LPC_CANAF_RAM_BASE + address)) = ID_low | ID_high;
  address += 4; 
  }
    
  /* Set group standard Frame */
  LPC_CANAF->SFF_GRP_sa = address;
  for ( i = 0; i < ACCF_IDEN_NUM; i += 2 )
  {
  ID_low = (i << 29) | (GRP_STD_ID << 16);
  ID_high = ((i+1) << 13) | (GRP_STD_ID << 0);
  *((volatile uint32_t *)(LPC_CANAF_RAM_BASE + address)) = ID_low | ID_high;
  address += 4; 
  }
 
  /* Set explicit extended Frame */ 
  LPC_CANAF->EFF_sa = address;
  for ( i = 0; i < ACCF_IDEN_NUM; i++  )
  {
  ID_low = (i << 29) | (EXP_EXT_ID << 0);
  *((volatile uint32_t *)(LPC_CANAF_RAM_BASE + address)) = ID_low;
  address += 4; 
  }

  /* Set group extended Frame */
  LPC_CANAF->EFF_GRP_sa = address;
  for ( i = 0; i < ACCF_IDEN_NUM; i++  )
  {
  ID_low = (i << 29) | (GRP_EXT_ID << 0);
  *((volatile uint32_t *)(LPC_CANAF_RAM_BASE + address)) = ID_low;
  address += 4; 
  }
   
  /* Set End of Table */
  LPC_CANAF->ENDofTable = address;
  return;
}


und zwar ist mein Problem das i addiert wird im laufe der Beschreibung. 
Die Table dient ja dazu bestimmte Identifier für den Controller bekannt 
zu machen so dass er diese durchlässt.
Ich habe nun mit dem explicit standard Frame getestet und hier ist es 
so, dass die Bits der verschiedenen Identifier so geschoben werden, dass 
es eine 32-Bit struktur gibt mit dem SCC (kennzeichnet den Controller). 
Laut dem Code kennzeichnet das i also den Cotnroller dies ist beim 
Eintritt 2 durch das verschieben kennzeichnet  es dann CAN2 jedoch für 
den lower Teil der Bitfolge wird i erhöht und spricht meiner meinung 
nach nun einen anderen Controller an oder?
Wenn ich nun eine Nachricht sende, so kommt diese auch durch jedoch nur 
mit dem upper Identifier, woran liegt das?

Vielen dank ich hoffe ihr habt das so alles verstanden wenn nicht dann 
erklär ich es einfach nochmal anders =)

Autor: Erwin Reuss (er-tronik)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das mit den Filtern ist schon so eine Sache, da bin ich auch noch nicht 
komplett durch. Für meinen Anwendungszweck funktioniert das jedenfalls 
schon wie im Folgenden beschrieben.
Für meinen Anwendungszweck muß ich die OBD-Adressen für CAN-11bit und 
CAN-29bit ausfiltern. Bereiche, die nicht gebraucht werden, müssen 
einfach mit dem aktuellen Wert von adr initialisiert werden.

static void CAN_SetFilter(void)
{
  u32 adr = 0;

  CANAF->AFMR = ACCF_OFF;              // Acceptance Filter OFF
  
  CANAF->SFF_sa = adr;
  CANAF->SFF_GRP_sa = adr; 
    // === Diesen Bereich auslassen, wenn keine 11-Bit Filter gebraucht werden
    *((vu32 *)(CANAF_RAM_BASE + adr)) = ((u16)Id11_lo << 16) | (u16)Id11_hi;
    adr += 4;
    //=============================================================
  CANAF->EFF_sa = adr;
  CANAF->EFF_GRP_sa = adr;
    // === Diesen Bereich auslassen, wenn keine 29-Bit Filter gebraucht werden
    *((vu32 *)(CANAF_RAM_BASE + adr)) = Id29_lo;
    adr += 4;
    *((vu32 *)(CANAF_RAM_BASE + adr)) = Id29_hi;
    adr += 4;
    //=============================================================
  CANAF->ENDofTable = adr;
  
  CANAF->AFMR = ACCF_ON;               // Acceptance Filter ON
}


void CAN_Init(void) 
{
  //....
  Id11_lo = 0x7E0;
  Id11_hi = 0x7EF;
  Id29_lo = 0x18DAF100; 
  Id29_hi = 0x18DAF1FF;
  CAN_SetFilter();
  //....
}

Autor: Tom (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
alles klar jetzt funktioniert es bei mir auch die for schleife vor dem 
ganzen ist absolut unnötig gewesen und jetzt kann ich auch mehrere 
Identifier zulassen.
Vielen dank für die super Hilfe =)

Autor: Lutz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tom schrieb:
> Vielen dank für die super Hilfe =)

Kein Problem, hab' ich doch gerne gemacht.

Duck und weg ...

Autor: Hoschi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Erwin Reuss schrieb:
> Ich finde es traurig, wenn Leute hier antworten, die selber nicht _genau_
> über das Thema Bescheid wissen.

Erwin Reuss schrieb:
> Das mit den Filtern ist schon so eine Sache, da bin ich auch noch nicht
> komplett durch.

Ach so ...

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.