Statistics
| Branch: | Tag: | Revision:

amiro-blt / Target / Source / ARMCM3_STM32 / can.c @ 470d0567

History | View | Annotate | Download (17.9 KB)

1
/************************************************************************************//**
2
* \file         Source\ARMCM3_STM32\can.c
3
* \brief        Bootloader CAN communication interface source file.
4
* \ingroup      Target_ARMCM3_STM32
5
* \internal
6
*----------------------------------------------------------------------------------------
7
*                          C O P Y R I G H T
8
*----------------------------------------------------------------------------------------
9
*   Copyright (c) 2011  by Feaser    http://www.feaser.com    All rights reserved
10
*
11
*----------------------------------------------------------------------------------------
12
*                            L I C E N S E
13
*----------------------------------------------------------------------------------------
14
* This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or
15
* modify it under the terms of the GNU General Public License as published by the Free
16
* Software Foundation, either version 3 of the License, or (at your option) any later
17
* version.
18
*
19
* OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
20
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
21
* PURPOSE. See the GNU General Public License for more details.
22
*
23
* You should have received a copy of the GNU General Public License along with OpenBLT.
24
* If not, see <http://www.gnu.org/licenses/>.
25
*
26
* A special exception to the GPL is included to allow you to distribute a combined work 
27
* that includes OpenBLT without being obliged to provide the source code for any 
28
* proprietary components. The exception text is included at the bottom of the license
29
* file <license.html>.
30
* 
31
* \endinternal
32
****************************************************************************************/
33

    
34

    
35
/****************************************************************************************
36
* Include files
37
****************************************************************************************/
38
#include "boot.h"                                /* bootloader generic header          */
39

    
40

    
41
#if (BOOT_COM_CAN_ENABLE > 0 || BOOT_GATE_CAN_ENABLE > 0)
42
/****************************************************************************************
43
* Type definitions
44
****************************************************************************************/
45
/** \brief CAN transmission mailbox layout. */
46
typedef struct
47
{
48
  volatile blt_int32u TIR;
49
  volatile blt_int32u TDTR;
50
  volatile blt_int32u TDLR;
51
  volatile blt_int32u TDHR;
52
} tCanTxMailBox;
53

    
54
/** \brief CAN reception FIFO mailbox layout. */
55
typedef struct
56
{
57
  volatile blt_int32u RIR;
58
  volatile blt_int32u RDTR;
59
  volatile blt_int32u RDLR;
60
  volatile blt_int32u RDHR;
61
} tCanRxFIFOMailBox; 
62

    
63
/** \brief CAN filter register layout. */
64
typedef struct
65
{
66
  volatile blt_int32u FR1;
67
  volatile blt_int32u FR2;
68
} tCanFilter;
69

    
70
/** \brief CAN controller register layout. */
71
typedef struct
72
{
73
  volatile blt_int32u MCR;
74
  volatile blt_int32u MSR;
75
  volatile blt_int32u TSR;
76
  volatile blt_int32u RF0R;
77
  volatile blt_int32u RF1R;
78
  volatile blt_int32u IER;
79
  volatile blt_int32u ESR;
80
  volatile blt_int32u BTR;
81
  blt_int32u          RESERVED0[88];
82
  tCanTxMailBox       sTxMailBox[3];
83
  tCanRxFIFOMailBox   sFIFOMailBox[2];
84
  blt_int32u          RESERVED1[12];
85
  volatile blt_int32u FMR;
86
  volatile blt_int32u FM1R;
87
  blt_int32u          RESERVED2;
88
  volatile blt_int32u FS1R;
89
  blt_int32u          RESERVED3;
90
  volatile blt_int32u FFA1R;
91
  blt_int32u          RESERVED4;
92
  volatile blt_int32u FA1R;
93
  blt_int32u          RESERVED5[8];
94
  tCanFilter          sFilterRegister[14];
95
} tCanRegs;                                           
96

    
97

    
98
/****************************************************************************************
99
* Macro definitions
100
****************************************************************************************/
101
/** \brief Reset request bit. */
102
#define CAN_BIT_RESET    ((blt_int32u)0x00008000)
103
/** \brief Initialization request bit. */
104
#define CAN_BIT_INRQ     ((blt_int32u)0x00000001)
105
/** \brief Initialization acknowledge bit. */
106
#define CAN_BIT_INAK     ((blt_int32u)0x00000001)
107
/** \brief Sleep mode request bit. */
108
#define CAN_BIT_SLEEP    ((blt_int32u)0x00000002)
109
/** \brief Filter 0 selection bit. */
110
#define CAN_BIT_FILTER0  ((blt_int32u)0x00000001)
111
/** \brief Filter init mode bit. */
112
#define CAN_BIT_FINIT    ((blt_int32u)0x00000001)
113
/** \brief Transmit mailbox 0 empty bit. */
114
#define CAN_BIT_TME0     ((blt_int32u)0x04000000)
115
/** \brief Transmit mailbox request bit. */
116
#define CAN_BIT_TXRQ     ((blt_int32u)0x00000001)
117
/** \brief Release FIFO 0 mailbox bit. */
118
#define CAN_BIT_RFOM0    ((blt_int32u)0x00000020)
119

    
120
#if (BOOT_GATE_CAN_ENABLE > 0)
121
blt_bool commandSend;
122
#endif /* BOOT_GATE_CAN_ENABLE > 0 */
123

    
124

    
125
/****************************************************************************************
126
* Register definitions
127
****************************************************************************************/
128
/** \brief Macro for accessing CAN controller registers. */
129
#define CANx             ((tCanRegs *) (blt_int32u)0x40006400)
130

    
131

    
132
/****************************************************************************************
133
* Type definitions
134
****************************************************************************************/
135
/** \brief Structure type for grouping CAN bus timing related information. */
136
typedef struct t_can_bus_timing
137
{
138
  blt_int8u tseg1;                                    /**< CAN time segment 1          */
139
  blt_int8u tseg2;                                    /**< CAN time segment 2          */
140
} tCanBusTiming;
141

    
142

    
143
/****************************************************************************************
144
* Local constant declarations
145
****************************************************************************************/
146
/** \brief CAN bittiming table for dynamically calculating the bittiming settings.
147
 *  \details According to the CAN protocol 1 bit-time can be made up of between 8..25 
148
 *           time quanta (TQ). The total TQ in a bit is SYNC + TSEG1 + TSEG2 with SYNC 
149
 *           always being 1. The sample point is (SYNC + TSEG1) / (SYNC + TSEG1 + SEG2) * 
150
 *           100%. This array contains possible and valid time quanta configurations with
151
 *           a sample point between 68..78%.
152
 */
153
static const tCanBusTiming canTiming[] =
154
{                       /*  TQ | TSEG1 | TSEG2 | SP  */
155
                        /* ------------------------- */
156
    {  5, 2 },          /*   8 |   5   |   2   | 75% */
157
    {  6, 2 },          /*   9 |   6   |   2   | 78% */
158
    {  6, 3 },          /*  10 |   6   |   3   | 70% */
159
    {  7, 3 },          /*  11 |   7   |   3   | 73% */
160
    {  8, 3 },          /*  12 |   8   |   3   | 75% */
161
    {  9, 3 },          /*  13 |   9   |   3   | 77% */
162
    {  9, 4 },          /*  14 |   9   |   4   | 71% */
163
    { 10, 4 },          /*  15 |  10   |   4   | 73% */
164
    { 11, 4 },          /*  16 |  11   |   4   | 75% */
165
    { 12, 4 },          /*  17 |  12   |   4   | 76% */
166
    { 12, 5 },          /*  18 |  12   |   5   | 72% */
167
    { 13, 5 },          /*  19 |  13   |   5   | 74% */
168
    { 14, 5 },          /*  20 |  14   |   5   | 75% */
169
    { 15, 5 },          /*  21 |  15   |   5   | 76% */
170
    { 15, 6 },          /*  22 |  15   |   6   | 73% */
171
    { 16, 6 },          /*  23 |  16   |   6   | 74% */
172
    { 16, 7 },          /*  24 |  16   |   7   | 71% */
173
    { 16, 8 }           /*  25 |  16   |   8   | 68% */
174
};
175

    
176

    
177
/************************************************************************************//**
178
** \brief     Search algorithm to match the desired baudrate to a possible bus 
179
**            timing configuration.
180
** \param     baud The desired baudrate in kbps. Valid values are 10..1000.
181
** \param     prescaler Pointer to where the value for the prescaler will be stored.
182
** \param     tseg1 Pointer to where the value for TSEG2 will be stored.
183
** \param     tseg2 Pointer to where the value for TSEG2 will be stored.
184
** \return    BLT_TRUE if the CAN bustiming register values were found, BLT_FALSE 
185
**            otherwise.
186
**
187
****************************************************************************************/
188
static blt_bool CanGetSpeedConfig(blt_int16u baud, blt_int16u *prescaler, 
189
                                  blt_int8u *tseg1, blt_int8u *tseg2)
190
{
191
  blt_int8u  cnt;
192

    
193
  /* loop through all possible time quanta configurations to find a match */
194
  for (cnt=0; cnt < sizeof(canTiming)/sizeof(canTiming[0]); cnt++)
195
  {
196
    if (((BOOT_CPU_SYSTEM_SPEED_KHZ/2) % (baud*(canTiming[cnt].tseg1+canTiming[cnt].tseg2+1))) == 0)
197
    {
198
      /* compute the prescaler that goes with this TQ configuration */
199
      *prescaler = (BOOT_CPU_SYSTEM_SPEED_KHZ/2)/(baud*(canTiming[cnt].tseg1+canTiming[cnt].tseg2+1));
200

    
201
      /* make sure the prescaler is valid */
202
      if ( (*prescaler > 0) && (*prescaler <= 1024) )
203
      {
204
        /* store the bustiming configuration */
205
        *tseg1 = canTiming[cnt].tseg1;
206
        *tseg2 = canTiming[cnt].tseg2;
207
        /* found a good bus timing configuration */
208
        return BLT_TRUE;
209
      }
210
    }
211
  }
212
  /* could not find a good bus timing configuration */
213
  return BLT_FALSE;
214
} /*** end of CanGetSpeedConfig ***/
215

    
216

    
217
/************************************************************************************//**
218
** \brief     Initializes the CAN controller and synchronizes it to the CAN bus.
219
** \return    none.
220
**
221
****************************************************************************************/
222
void CanInit(void)
223
{
224
  blt_int16u prescaler;
225
  blt_int8u  tseg1, tseg2;
226
  blt_bool   result;
227

    
228
#if (BOOT_GATE_CAN_ENABLE > 0)
229
  commandSend = BLT_FALSE;
230
#endif /* BOOT_GATE_CAN_ENABLE > 0 */
231

    
232
  /* the current implementation supports CAN1. throw an assertion error in case a 
233
   * different CAN channel is configured.  
234
   */
235
  ASSERT_CT(BOOT_COM_CAN_CHANNEL_INDEX == 0); 
236
  /* obtain bittiming configuration information */
237
  result = CanGetSpeedConfig(BOOT_COM_CAN_BAUDRATE/1000, &prescaler, &tseg1, &tseg2);
238
  ASSERT_RT(result == BLT_TRUE);
239
  /* disable all can interrupt. this driver works in polling mode */
240
  CANx->IER = (blt_int32u)0;
241
  /* set request to reset the can controller */
242
  CANx->MCR |= CAN_BIT_RESET ;
243
  /* wait for acknowledge that the can controller was reset */
244
  while ((CANx->MCR & CAN_BIT_RESET) != 0)
245
  {
246
    /* keep the watchdog happy */
247
    CopService();
248
  }
249
  /* exit from sleep mode, which is the default mode after reset */
250
  CANx->MCR &= ~CAN_BIT_SLEEP;
251
  /* set request to enter initialisation mode */
252
  CANx->MCR |= CAN_BIT_INRQ ;
253
  /* wait for acknowledge that initialization mode was entered */
254
  while ((CANx->MSR & CAN_BIT_INAK) == 0)
255
  {
256
    /* keep the watchdog happy */
257
    CopService();
258
  }
259
  /* configure the bittming */
260
  CANx->BTR = (blt_int32u)((blt_int32u)(tseg1 - 1) << 16) | \
261
              (blt_int32u)((blt_int32u)(tseg2 - 1) << 20) | \
262
              (blt_int32u)(prescaler - 1);
263
  /* set request to leave initialisation mode */
264
  CANx->MCR &= ~CAN_BIT_INRQ;
265
  /* wait for acknowledge that initialization mode was exited */
266
  while ((CANx->MSR & CAN_BIT_INAK) != 0)
267
  {
268
    /* keep the watchdog happy */
269
    CopService();
270
  }
271
  /* enter initialisation mode for the acceptance filter */
272
  CANx->FMR |= CAN_BIT_FINIT;
273
  /* deactivate filter 0 */
274
  CANx->FA1R &= ~CAN_BIT_FILTER0;
275
  /* 32-bit scale for the filter */
276
  CANx->FS1R |= CAN_BIT_FILTER0;
277
  /* open up the acceptance filter to receive all messages */
278
  CANx->sFilterRegister[0].FR1 = 0; 
279
  CANx->sFilterRegister[0].FR2 = 0; 
280
  /* select id/mask mode for the filter */
281
  CANx->FM1R &= ~CAN_BIT_FILTER0;
282
  /* FIFO 0 assignation for the filter */
283
  CANx->FFA1R &= ~CAN_BIT_FILTER0;
284
  /* filter activation */
285
  CANx->FA1R |= CAN_BIT_FILTER0;
286
  /* leave initialisation mode for the acceptance filter */
287
  CANx->FMR &= ~CAN_BIT_FINIT;
288
} /*** end of CanInit ***/
289

    
290

    
291
/************************************************************************************//**
292
** \brief     Transmits a packet formatted for the communication interface.
293
** \param     data     Pointer to byte array with data that it to be transmitted.
294
** \param     len      Number of bytes that are to be transmitted.
295
** \param     deviceID ID of the device the data has to be sent to.
296
** \return    none.
297
**
298
****************************************************************************************/
299
void CanTransmitPacket(blt_int8u *data, blt_int8u len, blt_int8u deviceID)
300
{
301
  /* make sure that transmit mailbox 0 is available */
302
  ASSERT_RT((CANx->TSR&CAN_BIT_TME0) == CAN_BIT_TME0);
303
  /* build the message identifier */
304
  CANx->sTxMailBox[0].TIR &= CAN_BIT_TXRQ;
305

    
306
  blt_int32u address;
307
#if (BOOT_GATE_CAN_ENABLE > 0)
308
  if (deviceID == 0) {
309
#endif /* BOOT_GATE_CAN_ENABLE > 0 */
310
    address = (blt_int32u)BOOT_COM_CAN_TX_MSG_ID;
311
#if (BOOT_GATE_CAN_ENABLE > 0)
312
    commandSend = BLT_FALSE;
313
  } else {
314
    address = ((blt_int32u)BOOT_COM_CAN_RX_MSG_ID | (blt_int32u)deviceID);
315
    commandSend = BLT_TRUE;
316
  }
317
#endif /* BOOT_GATE_CAN_ENABLE > 0 */
318

    
319
  /* init variables */
320
  blt_int8u canData[8];
321
  blt_int8u restLen = len;
322
  blt_int8u canIdx = 0;
323

    
324
  /* send the given package in 8 byte packages */
325
  while (restLen > 0) {
326

    
327
    CANx->sTxMailBox[0].TIR |= (address << 21);
328
    /* store the message date length code (DLC) */
329
    if (restLen > 7) {
330
      CANx->sTxMailBox[0].TDTR = 8;
331
    } else {
332
      CANx->sTxMailBox[0].TDTR = restLen+1;
333
    }
334
    /* Load max 8 bytes into message data bytes */
335
    canData[0] = restLen;
336
    canIdx = 1;
337
    while (restLen > 0 && canIdx < 8) {
338
      canData[canIdx] = data[len-restLen];
339
      canIdx++;
340
      restLen--;
341
    }
342
    /* fill rest with nulls */
343
    while (canIdx < 8) {
344
      canData[canIdx] = 0;
345
      canIdx++;
346
    }
347
    /* store the message data bytes */
348
    CANx->sTxMailBox[0].TDLR = (((blt_int32u)canData[3] << 24) | \
349
                                ((blt_int32u)canData[2] << 16) | \
350
                                ((blt_int32u)canData[1] <<  8) | \
351
                                ((blt_int32u)canData[0]));
352
    CANx->sTxMailBox[0].TDHR = (((blt_int32u)canData[7] << 24) | \
353
                                ((blt_int32u)canData[6] << 16) | \
354
                                ((blt_int32u)canData[5] <<  8) | \
355
                                ((blt_int32u)canData[4]));
356
    /* request the start of message transmission */
357
    CANx->sTxMailBox[0].TIR |= CAN_BIT_TXRQ;
358
    /* wait for transmit completion */
359
    while ((CANx->TSR&CAN_BIT_TME0) == 0)
360
    {
361
      /* keep the watchdog happy */
362
      CopService();
363
    }
364

    
365
  }
366
} /*** end of CanTransmitPacket ***/
367

    
368

    
369
/************************************************************************************//**
370
** \brief     Receives a communication interface packet if one is present.
371
** \param     data Pointer to byte array where the data is to be stored.
372
** \return    Length of message (if the message is invalid, the length will be 0).
373
**
374
****************************************************************************************/
375
blt_int8u CanReceivePacket(blt_int8u *data)
376
{
377
  blt_int32u rxMsgId;
378
  blt_bool   result = BLT_FALSE;
379
  blt_int8u  length = 0;
380

    
381
  static blt_int8u readData[BOOT_COM_RX_MAX_DATA];
382
  static blt_int8u receivedLen = 0;
383
  static blt_int8u lastLen = 0;
384
  static blt_int8u toReceive = 0;
385
  blt_int8u canData[8];
386
  blt_int8u restLen;
387
  blt_int8u canLength;
388

    
389
  /* check if a new message was received */
390
  if ((CANx->RF0R&(blt_int32u)0x00000003) > 0)
391
  {
392
    /* read out the message identifier */
393
    rxMsgId = (blt_int32u)0x000007FF & (CANx->sFIFOMailBox[0].RIR >> 21);
394
    /* is this the packet identifier */
395

    
396
    blt_int32u compID;
397
#if (BOOT_GATE_CAN_ENABLE > 0)
398
    if (commandSend == BLT_TRUE) {
399
      compID = (blt_int32u)BOOT_COM_CAN_TX_MSG_ID;
400
    } else {
401
#endif /* BOOT_GATE_CAN_ENABLE > 0 */
402
      compID = (blt_int32u)BOOT_COM_CAN_RX_MSG_ID | (blt_int32u)BOOT_COM_DEVICE_ID;
403
#if (BOOT_GATE_CAN_ENABLE > 0)
404
    }
405
#endif /* BOOT_GATE_CAN_ENABLE > 0 */
406

    
407
    if (rxMsgId == compID)
408
    {
409
#if (BOOT_GATE_CAN_ENABLE > 0)
410
      commandSend = BLT_FALSE;
411
#endif /* BOOT_GATE_CAN_ENABLE > 0 */
412
      result = BLT_TRUE;
413

    
414
      /* save length */
415
      canLength = (blt_int8u)0x0F & CANx->sFIFOMailBox[0].RDTR;
416
      /* store the received packet data */
417
      canData[0] = (blt_int8u)0xFF & CANx->sFIFOMailBox[0].RDLR;
418
      canData[1] = (blt_int8u)0xFF & (CANx->sFIFOMailBox[0].RDLR >> 8);
419
      canData[2] = (blt_int8u)0xFF & (CANx->sFIFOMailBox[0].RDLR >> 16);
420
      canData[3] = (blt_int8u)0xFF & (CANx->sFIFOMailBox[0].RDLR >> 24);
421
      canData[4] = (blt_int8u)0xFF & CANx->sFIFOMailBox[0].RDHR;
422
      canData[5] = (blt_int8u)0xFF & (CANx->sFIFOMailBox[0].RDHR >> 8);
423
      canData[6] = (blt_int8u)0xFF & (CANx->sFIFOMailBox[0].RDHR >> 16);
424
      canData[7] = (blt_int8u)0xFF & (CANx->sFIFOMailBox[0].RDHR >> 24);
425

    
426
      /* Store rest length of package and check if possible */
427
      if (receivedLen == 0) {
428
        toReceive = canData[0];
429
        lastLen = canData[0];
430
      } else {
431
        restLen = canData[0];
432
        if (lastLen-restLen != 7) {
433
          // package has been lost - but nothing happens
434
        }
435
        lastLen = restLen;
436
      }
437

    
438
      /* store data in data package */
439
      blt_int8u idx;
440
      for (idx=1; idx < canLength; idx++) {
441
        readData[receivedLen] = canData[idx];
442
        receivedLen++;
443
      }
444

    
445
      /* check if full package has been received */
446
      if (receivedLen >= toReceive) {
447
        receivedLen = 0;
448
        for (idx = 0; idx < toReceive; idx++) {
449
          data[idx] = readData[idx];
450
        }
451
        length = toReceive;
452
      } else {
453
        length = 0;
454
      }
455
    }
456
    /* release FIFO0 */
457
    CANx->RF0R |= CAN_BIT_RFOM0;
458
  }
459
  return length;
460
} /*** end of CanReceivePacket ***/
461
#endif /* BOOT_COM_CAN_ENABLE > 0  || BOOT_GATE_CAN_ENABLE > 0 */
462

    
463

    
464
/*********************************** end of can.c **************************************/