Author Topic: Need help powering up a car radio (ntg4 rer / MYGIG Uconnect 730N) on the bench  (Read 8380 times)

0 Members and 1 Guest are viewing this topic.

Offline poot36Topic starter

  • Frequent Contributor
  • **
  • Posts: 678
  • Country: ca
I have having trouble getting a ntg4 rer / MYGIG Uconnect 730N radio powered up on the bench.  I have found that it only has 12V and GND connections on the plug on the back (no ACC connection) and when I apply power to them it briefly spikes as the caps charge and then settles down to 0.30ma or so of draw.  I have found that if I press the disk eject button I get a quick spike of current to round 700 to 900ma and that is it.  I have done some research online and have found that this unit needs a Can bus signal to turn on and stay powered up.  The only CAN bus hardware I have is a STM32 blue pill board, a clone CAN bus transceiver chip (model VC1040 clone of TJA1040) from a partially broken OBDII dongle (damaged the main micro chip when trying to mod it for additional protocol support) and a Android Auto head unit made by XY Auto model YT9216-ver0.1 with a MCU version of 3.1.  I have found this software for the STM32 chip: https://github.com/nopnop2002/Arduino-STM32-CAN but am unsure if it is what I need to make this work.  The Android Auto unit clams to support CAN bus with a breakout box which I am going to guess is just a transceiver chip.  There is a Can bus information section in the service menu that I may be able to use but it could just be for monitoring the Can bus messages and not for sending them.  The issue is the radio is intermittently powering on and I want to rule out the car as the cause of the issue.
« Last Edit: May 09, 2021, 09:24:35 pm by poot36 »
 

Offline kripton2035

  • Super Contributor
  • ***
  • Posts: 2581
  • Country: fr
    • kripton2035 schematics repository
well wouldn't it easier to try the radio in another car ?
 

Offline poot36Topic starter

  • Frequent Contributor
  • **
  • Posts: 678
  • Country: ca
I do not have access to another car that would support this radio sadly.  And even if I did if there is a fault in the radio it may damage a working car and I would not want to risk that.
 

Offline dc101

  • Regular Contributor
  • *
  • Posts: 220
  • Country: us
I would buy a Raspberry Pi CAN bus shield, there are several different versions and plenty of software available for them. Much easier to run command-line Linux utils to capture and playback data then messing around with some microcontroller. Some co-workers of mine have successfully used can shields in the past to do exactly what you're trying to do.

For software something like this might work https://github.com/linux-can/can-utils  There are dozens of other software packages out there that can do can bus capture and replay, you'll just have to do a bit of google work to make sure the can bus shield you buy is supported by the can bus capture/replay software you intend to use.

You'll also need to do some research to determine what bus the radio is on so you know which bus you need to monitor. Most cars have at least 2 separate can buses, some newer cars have 3 or 4, but typically there is at least a low-speed and a high-speed can bus. Most non-safety traffic (like the radio) will be on the low-speed bus. For my Ford Fusion, the can bus is documented in the wiring diagram manual. I was able to find a few can bus schematics on line, but ultimately I just ended up buying a used manual off eBay for pretty cheap.

Hook your rpi can bus monitor to your vehicle, take a few captures of turning the radio on (don't record the power-off). Then you should be able to take those captures and play them back with the shield connected to your radio. The good news is that since you're only replaying the data to your radio, it is safe to replay the entire capture without having to try and isolate the specific power-on message. The other can bus traffic will be ignored by the radio. If you were to replay the traffic into your car's can bus while the car was on, well then that might cause some issues depending on the traffic and how sensitive your car is.
 
The following users thanked this post: edavid

Offline poot36Topic starter

  • Frequent Contributor
  • **
  • Posts: 678
  • Country: ca
I am really trying to avoid buying more stuff that I am going to only use once.  The radio came from a coworker that found out that I know stuff about electronics and I thought it would be a easy thing to fix.  How wrong I was.  I do not have access to the car.   The coworker does have a multimeter and I have instructed them to measure the voltage on the Can bus lines that are on the plug to the radio so hopefully they will find an issue there.  I am just wondering if I can make it work with the tools I have right now.  Still trying to figure out how to get the USB serial port working on the blue pill board after I have flashed it, it keeps coming up as a Maple DFU device and not as a com port.  I have it flashed with this bootloader: https://github.com/rogerclarkmelbourne/STM32duino-bootloader/blob/master/binaries/generic_boot20_pc13.bin and am using this: https://github.com/stm32duino/BoardManagerFiles/raw/master/package_stmicroelectronics_index.json for the board support.  Not sure if that is a compatible combination or not as this page: https://github.com/nopnop2002/Arduino-STM32-CAN mentions that it will not work with the board support for the bootloader I have on the chip but makes no mention of if I can use the bootloader from there or not.  I have enabled the USB CDC mode in the tools menu of the Arduino program and this has made an unknown USB device show up in device manager.
« Last Edit: May 09, 2021, 11:14:54 pm by poot36 »
 

Offline dc101

  • Regular Contributor
  • *
  • Posts: 220
  • Country: us
Ignoring the can bus hardware for now, without access to the vehicle it may be pretty hard to determine the proper message to turn on the radio. Each can bus frame has an ID that indicates the vehicle sub component and a data section that usually contains values for several different fields. For example, the engine ecu might be ID 123, followed by a data field that might contain the value for the air flow sensor, air temp, coolant temp etc... all within a single 64-bit value.

I'm sure there are other ways, but it seems like there are a couple of options. Research the vehicle type the radio belongs to and determine if anyone has previously identified the radio can bus messages. Check on vehicle forums to see if someone with the same vehicle could do can bus captures of the radio powering on. Less likely, but still worth looking into, ask a dealer if they can provide you with the information. Or you can try and fuzz the can bus by generating packets with random ids and data until you find something that works.

IMO I would be more focused on trying to determine what the can bus message is, or how to obtain a can bus packet from the appropriate vehicle, than the actual hardware to generate can bus messages. The hardware part has been done at great length and there is a plethora of information available on the topic, so once you know how to activate the radio, then just like you mentioned it becomes a decision about how much your time is worth as far as which hardware solution you decide to go with.

Here's some sample data that I pulled from a log for my old Mazda, I'm just filtering on one random ID, but it's just to give you an idea of what real can traffic looks like. So the challenge with reversing can is to determine which one of those 8 bytes in the data field are related to each other. Are they a single value, are there multiple values etc...
ID:0x160:STD:DLC:8:DATA:0x0A:0xF5:0x00:0x00:0x04:0x04:0x5D:0x00:
ID:0x160:STD:DLC:8:DATA:0x0A:0xF5:0x00:0x00:0x04:0x04:0x5D:0x00:
ID:0x160:STD:DLC:8:DATA:0x0A:0xF3:0x00:0x00:0x04:0x03:0x5D:0x00:
ID:0x160:STD:DLC:8:DATA:0x0A:0xF3:0x00:0x00:0x04:0x03:0x5D:0x00:
ID:0x160:STD:DLC:8:DATA:0x0A:0xF2:0x00:0x00:0x04:0x02:0x5D:0x00:
ID:0x160:STD:DLC:8:DATA:0x0A:0xF2:0x00:0x00:0x04:0x02:0x5D:0x00:
ID:0x160:STD:DLC:8:DATA:0x0A:0xF0:0x00:0x00:0x03:0xFF:0x5D:0x00:
ID:0x160:STD:DLC:8:DATA:0x0A:0xF0:0x00:0x00:0x03:0xFF:0x5D:0x00:
ID:0x160:STD:DLC:8:DATA:0x0A:0xEF:0x00:0x00:0x04:0x00:0x5D:0x00:
ID:0x160:STD:DLC:8:DATA:0x0A:0xEF:0x00:0x00:0x04:0x00:0x5D:0x00:
ID:0x160:STD:DLC:8:DATA:0x0A:0xEF:0x00:0x00:0x04:0x00:0x5D:0x00:
ID:0x160:STD:DLC:8:DATA:0x0A:0xED:0x00:0x00:0x03:0xFC:0x5D:0x00:
ID:0x160:STD:DLC:8:DATA:0x0A:0xEB:0x00:0x00:0x03:0xF6:0x5D:0x00:
ID:0x160:STD:DLC:8:DATA:0x0A:0xEB:0x00:0x00:0x03:0xF6:0x5D:0x00:
ID:0x160:STD:DLC:8:DATA:0x0A:0xE9:0x00:0x00:0x03:0xF4:0x5D:0x00:
ID:0x160:STD:DLC:8:DATA:0x0A:0xE7:0x00:0x00:0x03:0xF3:0x5D:0x00:
ID:0x160:STD:DLC:8:DATA:0x0A:0xE7:0x00:0x00:0x03:0xF3:0x5D:0x00:
ID:0x160:STD:DLC:8:DATA:0x0A:0xE7:0x00:0x00:0x03:0xF3:0x5D:0x00:
 

Offline poot36Topic starter

  • Frequent Contributor
  • **
  • Posts: 678
  • Country: ca
I think I found the commands I need to send here: http://canhack.org/board/viewtopic.php?f=1&t=161&p=822&hilit=bench#p822  Would have to get the hardware and software setup to test them out though.
 

Offline poot36Topic starter

  • Frequent Contributor
  • **
  • Posts: 678
  • Country: ca
I am getting closer, with this code I can get the radio to continually draw 700ma to 1.3A of power but not fully turn on.  I am just spamming it right now though.

void loop() {
  CAN_msg_t CAN_TX_msg;
  CAN_msg_t CAN_RX_msg;

  CAN_TX_msg.data[0] = 0x00;
  CAN_TX_msg.data[1] = 0x01;
  CAN_TX_msg.data[2] = 0x02;
  CAN_TX_msg.data[3] = 0x03;
  CAN_TX_msg.data[4] = 0x04;
  CAN_TX_msg.data[5] = 0x05;
  CAN_TX_msg.data[6] = 0x06;
  CAN_TX_msg.data[7] = 0x07;
  CAN_TX_msg.len = frameLength;

  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    if ( ( counter % 2) == 0) {
      CAN_TX_msg.type = DATA_FRAME;
      if (CAN_TX_msg.len == 0) CAN_TX_msg.type = REMOTE_FRAME;
      CAN_TX_msg.format = STANDARD_FORMAT;
      CAN_TX_msg.id = 0x000;
    } else {
      CAN_TX_msg.type = DATA_FRAME;
      if (CAN_TX_msg.len == 0) CAN_TX_msg.type = REMOTE_FRAME;
      CAN_TX_msg.format = STANDARD_FORMAT;
      CAN_TX_msg.id = 0x400;
    }
    CANSend(&CAN_TX_msg);
    frameLength++;
    if (frameLength == 9) frameLength = 0;
    counter++;
  }

I do not have a termination resistor in the circuit could that be the issue?  Or do I have to figure out the code more so that I can send a repeating sequence of the same code instead of a incrementing data packet?
 

Offline dc101

  • Regular Contributor
  • *
  • Posts: 220
  • Country: us
Is that code you found on the can bus forum for the same model vehicle/radio as the one you have, if not I would guess that it's most likely not the correct code/data required to turn the radio on. The increase in current is probably a good sign though since it seems like the radio is monitoring the bus looking for relevant codes?

 

Offline poot36Topic starter

  • Frequent Contributor
  • **
  • Posts: 678
  • Country: ca
This is slightly modified code from a example of how to use Can bus on the STM32f103 chip from here: https://github.com/nopnop2002/Arduino-STM32-CAN  as you can see from the screenshots it is just an incrementing code.  I have removed the extended ID section and replaced it with another standard ID section.  I am sending ID 400 and ID 000 alternating with incrementing data.  As I am not a coder I don't really understand how I would change this to just repeat one code until power off.
 

Offline poot36Topic starter

  • Frequent Contributor
  • **
  • Posts: 678
  • Country: ca
I got the serial output redirected to Serial 3 on the STM32 as the USB USART does not show up correctly (device manager shows unknown device) and I have attached to this post the log file of the output as it is to long for this forum.  I think it is looping.
 

Offline dc101

  • Regular Contributor
  • *
  • Posts: 220
  • Country: us
That's understandable, what I'm asking is, if you know for a fact that ID 400 is what your radio is expecting to receive? Have you found any documentation for your radio/vehicle that indicates this is the ID of the radio? Once you determine the ID, then you can move on to trying to determine what the data sent along with the ID is supposed to look like.

This is slightly modified code from a example of how to use Can bus on the STM32f103 chip from here: https://github.com/nopnop2002/Arduino-STM32-CAN  as you can see from the screenshots it is just an incrementing code.  I have removed the extended ID section and replaced it with another standard ID section.  I am sending ID 400 and ID 000 alternating with incrementing data.  As I am not a coder I don't really understand how I would change this to just repeat one code until power off.
 

Offline poot36Topic starter

  • Frequent Contributor
  • **
  • Posts: 678
  • Country: ca
I found that out from this other forum post from here http://canhack.org/board/viewtopic.php?f=1&t=161&p=822&hilit=bench#p822:

    stephan wrote:
    I did some direct discussion with colletjr in between and I think it's time to post some results to all involved here.
    With help from colletjr I could start the radio. And in further process I found out that a '000 63 00 00 00 00 00' which is sent at least every 800ms is fully sufficient to let the radio stay alive. It's only the wiring which is of influence on the actions happening there. Colletjr is right to use a short cable (twisted or non-twisted) without resistor-termination; ground should be connected. Listening to the communication of a radio with an extra can-controller (Atmel At90Can128 which sends the wake-ups e.g. every 500ms) shows that any change of the wiring leads to a missing acknowledge which is expected to be sent by the radio. In this case it seems that the radio is receiving the signal and reacts to this by turning on for a second. But as no acknowledge is received by the sender (the connected controller) this one repeats the wake-up signal permanently as fast as it can. All together results in a cycling wake-up of the radio for a second an a pause of approx. 4 seconds.
    To complete some data: The radio I played with is a 2004 with integrated mp3-6CD-changer with 2 big adjusting knobs from a 2005 Chrysler 300c.

    Hope this helps someone.
    If anybody knows the code for switching on the lights -please post. The '1C8 13...' or '1C8 03...' from the can-logger is not working.

You have to send any 4xx ID to the radio. For example..

MyID = 0x415; // this can be any number between 0x400 to 0x4ff except for 0x416 and as long as no other modules are on the bus.
TX_Data[0] = 0xfd;
TX_Data[1] = 0x16; // radio id 0x416
TX_Data[2] = 0x3f;
TX_Data[3] = 0xff;
TX_Data[4] = 0xff;
TX_Data[5] = 0xff;
TX_Data[6] = 0xff;
TX_Data[7] = 0xff;
 

Offline poot36Topic starter

  • Frequent Contributor
  • **
  • Posts: 678
  • Country: ca
Well I just found this image that I have attached to this post from this forum http://canhack.org/board/viewtopic.php?f=2&t=1173&sid=9b615b8b1be4d52afb62f2addbd51f19:

Looks like I need to figure out how to send a 6 bit code along with a 8 bit code and the radio should turn on (I hope).  Not sure how to do this though.

Here is the code I am using:
Code: [Select]
#define DEBUG 0

//                      RX    TX
HardwareSerial Serial3(PA10, PA9);

/* Symbolic names for bit rate of CAN message                                */
typedef enum {CAN_50KBPS, CAN_100KBPS, CAN_125KBPS, CAN_250KBPS, CAN_500KBPS, CAN_1000KBPS} BITRATE;

/* Symbolic names for formats of CAN message                                 */
typedef enum {STANDARD_FORMAT = 0, EXTENDED_FORMAT} CAN_FORMAT;

/* Symbolic names for type of CAN message                                    */
typedef enum {DATA_FRAME = 0, REMOTE_FRAME}         CAN_FRAME;


typedef struct
{
  uint32_t id;        /* 29 bit identifier                               */
  uint8_t  data[8];   /* Data field                                      */
  uint8_t  len;       /* Length of data field in bytes                   */
  uint8_t  ch;        /* Object channel(Not use)                         */
  uint8_t  format;    /* 0 - STANDARD, 1- EXTENDED IDENTIFIER            */
  uint8_t  type;      /* 0 - DATA FRAME, 1 - REMOTE FRAME                */
} CAN_msg_t;

typedef const struct
{
  uint8_t TS2;
  uint8_t TS1;
  uint8_t BRP;
} CAN_bit_timing_config_t;

CAN_bit_timing_config_t can_configs[6] = {{2, 13, 45}, {2, 15, 20}, {2, 13, 18}, {2, 13, 9}, {2, 15, 4}, {2, 15, 2}};

/**
 * Print registers.
*/
void printRegister(char * buf, uint32_t reg) {
  if (DEBUG == 0) return;
  Serial3.print(buf);
  Serial3.print(reg, HEX);
  Serial3.println();
}

/**
 * Initializes the CAN filter registers.
 *
 * @preconditions   - This register can be written only when the filter initialization mode is set (FINIT=1) in the CAN_FMR register.
 * @params: index   - Specified filter index. index 27:14 are available in connectivity line devices only.
 * @params: scale   - Select filter scale.
 *                    0: Dual 16-bit scale configuration
 *                    1: Single 32-bit scale configuration
 * @params: mode    - Select filter mode.
 *                    0: Two 32-bit registers of filter bank x are in Identifier Mask mode
 *                    1: Two 32-bit registers of filter bank x are in Identifier List mode
 * @params: fifo    - Select filter assigned.
 *                    0: Filter assigned to FIFO 0
 *                    1: Filter assigned to FIFO 1
 * @params: bank1   - Filter bank register 1
 * @params: bank2   - Filter bank register 2
 *
 */
void CANSetFilter(uint8_t index, uint8_t scale, uint8_t mode, uint8_t fifo, uint32_t bank1, uint32_t bank2) {
  if (index > 27) return;

  CAN1->FA1R &= ~(0x1UL<<index);               // Deactivate filter

  if (scale == 0) {
    CAN1->FS1R &= ~(0x1UL<<index);             // Set filter to Dual 16-bit scale configuration
  } else {
    CAN1->FS1R |= (0x1UL<<index);              // Set filter to single 32 bit configuration
  }
    if (mode == 0) {
    CAN1->FM1R &= ~(0x1UL<<index);             // Set filter to Mask mode
  } else {
    CAN1->FM1R |= (0x1UL<<index);              // Set filter to List mode
  }

  if (fifo == 0) {
    CAN1->FFA1R &= ~(0x1UL<<index);            // Set filter assigned to FIFO 0
  } else {
    CAN1->FFA1R |= (0x1UL<<index);             // Set filter assigned to FIFO 1
  }

  CAN1->sFilterRegister[index].FR1 = bank1;    // Set filter bank registers1
  CAN1->sFilterRegister[index].FR2 = bank2;    // Set filter bank registers2

  CAN1->FA1R |= (0x1UL<<index);                // Activate filter

}

/**
 * Initializes the CAN controller with specified bit rate.
 *
 * @params: bitrate - Specified bitrate. If this value is not one of the defined constants, bit rate will be defaulted to 125KBS
 * @params: remap   - Select CAN port.
 *                    =0:CAN_RX mapped to PA11, CAN_TX mapped to PA12
 *                    =1:Not used
 *                    =2:CAN_RX mapped to PB8, CAN_TX mapped to PB9 (not available on 36-pin package)
 *                    =3:CAN_RX mapped to PD0, CAN_TX mapped to PD1 (available on 100-pin and 144-pin package)
 *
 */
bool CANInit(BITRATE bitrate, int remap)
{
  // Reference manual
  // [url=https://www.st.com/content/ccc/resource/technical/document/reference_manual/59/b9/ba/7f/11/af/43/d5/CD00171190.pdf/files/CD00171190.pdf/jcr:content/translations/en.CD00171190.pdf]https://www.st.com/content/ccc/resource/technical/document/reference_manual/59/b9/ba/7f/11/af/43/d5/CD00171190.pdf/files/CD00171190.pdf/jcr:content/translations/en.CD00171190.pdf[/url]

  RCC->APB1ENR |= 0x2000000UL;       // Enable CAN clock
  RCC->APB2ENR |= 0x1UL;             // Enable AFIO clock
  AFIO->MAPR   &= 0xFFFF9FFF;        // reset CAN remap
                                     // CAN_RX mapped to PA11, CAN_TX mapped to PA12

  if (remap == 0) {
    RCC->APB2ENR |= 0x4UL;           // Enable GPIOA clock
    GPIOA->CRH   &= ~(0xFF000UL);    // Configure PA12(0b0000) and PA11(0b0000)
                                     // 0b0000
                                     //   MODE=00(Input mode)
                                     //   CNF=00(Analog mode)

    GPIOA->CRH   |= 0xB8FFFUL;       // Configure PA12(0b1011) and PA11(0b1000)
                                     // 0b1011
                                     //   MODE=11(Output mode, max speed 50 MHz)
                                     //   CNF=10(Alternate function output Push-pull
                                     // 0b1000
                                     //   MODE=00(Input mode)
                                     //   CNF=10(Input with pull-up / pull-down)
                                     
    GPIOA->ODR |= 0x1UL << 12;       // PA12 Upll-up
   
  }
                               
  if (remap == 2) {
    AFIO->MAPR   |= 0x00004000;      // set CAN remap
                                     // CAN_RX mapped to PB8, CAN_TX mapped to PB9 (not available on 36-pin package)

    RCC->APB2ENR |= 0x8UL;           // Enable GPIOB clock
    GPIOB->CRH   &= ~(0xFFUL);       // Configure PB9(0b0000) and PB8(0b0000)
                                     // 0b0000
                                     //   MODE=00(Input mode)
                                     //   CNF=00(Analog mode)

    GPIOB->CRH   |= 0xB8UL;          // Configure PB9(0b1011) and PB8(0b1000)
                                     // 0b1011
                                     //   MODE=11(Output mode, max speed 50 MHz)
                                     //   CNF=10(Alternate function output Push-pull
                                     // 0b1000
                                     //   MODE=00(Input mode)
                                     //   CNF=10(Input with pull-up / pull-down)
                                     
    GPIOB->ODR |= 0x1UL << 8;        // PB8 Upll-up
  }
 
  if (remap == 3) {
    AFIO->MAPR   |= 0x00005000;      // set CAN remap
                                     // CAN_RX mapped to PD0, CAN_TX mapped to PD1 (available on 100-pin and 144-pin package)

    RCC->APB2ENR |= 0x20UL;          // Enable GPIOD clock
    GPIOD->CRL   &= ~(0xFFUL);       // Configure PD1(0b0000) and PD0(0b0000)
                                     // 0b0000
                                     //   MODE=00(Input mode)
                                     //   CNF=00(Analog mode)

    GPIOD->CRH   |= 0xB8UL;          // Configure PD1(0b1011) and PD0(0b1000)
                                     // 0b1000
                                     //   MODE=00(Input mode)
                                     //   CNF=10(Input with pull-up / pull-down)
                                     // 0b1011
                                     //   MODE=11(Output mode, max speed 50 MHz)
                                     //   CNF=10(Alternate function output Push-pull
                                     
    GPIOD->ODR |= 0x1UL << 0;        // PD0 Upll-up
  }

  CAN1->MCR |= 0x1UL;                   // Require CAN1 to Initialization mode
  while (!(CAN1->MSR & 0x1UL));         // Wait for Initialization mode

  //CAN1->MCR = 0x51UL;                 // Hardware initialization(No automatic retransmission)
  CAN1->MCR = 0x41UL;                   // Hardware initialization(With automatic retransmission)
   
  // Set bit rates
  CAN1->BTR &= ~(((0x03) << 24) | ((0x07) << 20) | ((0x0F) << 16) | (0x1FF));
  CAN1->BTR |=  (((can_configs[bitrate].TS2-1) & 0x07) << 20) | (((can_configs[bitrate].TS1-1) & 0x0F) << 16) | ((can_configs[bitrate].BRP-1) & 0x1FF);

  // Configure Filters to default values
  CAN1->FMR  |=   0x1UL;                // Set to filter initialization mode
  CAN1->FMR  &= 0xFFFFC0FF;             // Clear CAN2 start bank

  // bxCAN has 28 filters.
  // These filters are used for both CAN1 and CAN2.
  // STM32F103 has only CAN1, so all 28 are used for CAN1
  CAN1->FMR  |= 0x1C << 8;              // Assign all filters to CAN1

  // Set fileter 0
  // Single 32-bit scale configuration
  // Two 32-bit registers of filter bank x are in Identifier Mask mode
  // Filter assigned to FIFO 0
  // Filter bank register to all 0
  CANSetFilter(0, 1, 0, 0, 0x0UL, 0x0UL);
 
  CAN1->FMR   &= ~(0x1UL);              // Deactivate initialization mode

  uint16_t TimeoutMilliseconds = 1000;
  bool can1 = false;
  CAN1->MCR   &= ~(0x1UL);              // Require CAN1 to normal mode

  // Wait for normal mode
  // If the connection is not correct, it will not return to normal mode.
  for (uint16_t wait_ack = 0; wait_ack < TimeoutMilliseconds; wait_ack++) {
    if ((CAN1->MSR & 0x1UL) == 0) {
      can1 = true;
      break;
    }
    delayMicroseconds(1000);
  }
  //Serial3.print("can1=");
  //Serial3.println(can1);
  if (can1) {
    Serial3.println("CAN1 initialize ok");
  } else {
    Serial3.println("CAN1 initialize fail!!");
    return false;
  }
  return true;
}


#define STM32_CAN_TIR_TXRQ              (1U << 0U)  // Bit 0: Transmit Mailbox Request
#define STM32_CAN_RIR_RTR               (1U << 1U)  // Bit 1: Remote Transmission Request
#define STM32_CAN_RIR_IDE               (1U << 2U)  // Bit 2: Identifier Extension
#define STM32_CAN_TIR_RTR               (1U << 1U)  // Bit 1: Remote Transmission Request
#define STM32_CAN_TIR_IDE               (1U << 2U)  // Bit 2: Identifier Extension

#define CAN_EXT_ID_MASK                 0x1FFFFFFFU
#define CAN_STD_ID_MASK                 0x000007FFU
 
/**
 * Decodes CAN messages from the data registers and populates a
 * CAN message struct with the data fields.
 *
 * @preconditions A valid CAN message is received
 * @params CAN_rx_msg - CAN message structure for reception
 *
 */
void CANReceive(CAN_msg_t* CAN_rx_msg)
{
  uint32_t id = CAN1->sFIFOMailBox[0].RIR;
  if ((id & STM32_CAN_RIR_IDE) == 0) { // Standard frame format
      CAN_rx_msg->format = STANDARD_FORMAT;;
      CAN_rx_msg->id = (CAN_STD_ID_MASK & (id >> 21U));
  }
  else {                               // Extended frame format
      CAN_rx_msg->format = EXTENDED_FORMAT;;
      CAN_rx_msg->id = (CAN_EXT_ID_MASK & (id >> 3U));
  }

  if ((id & STM32_CAN_RIR_RTR) == 0) { // Data frame
      CAN_rx_msg->type = DATA_FRAME;
  }
  else {                               // Remote frame
      CAN_rx_msg->type = REMOTE_FRAME;
  }

 
  CAN_rx_msg->len = (CAN1->sFIFOMailBox[0].RDTR) & 0xFUL;
 
  CAN_rx_msg->data[0] = 0xFFUL &  CAN1->sFIFOMailBox[0].RDLR;
  CAN_rx_msg->data[1] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDLR >> 8);
  CAN_rx_msg->data[2] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDLR >> 16);
  CAN_rx_msg->data[3] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDLR >> 24);
  CAN_rx_msg->data[4] = 0xFFUL &  CAN1->sFIFOMailBox[0].RDHR;
  CAN_rx_msg->data[5] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDHR >> 8);
  CAN_rx_msg->data[6] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDHR >> 16);
  CAN_rx_msg->data[7] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDHR >> 24);

  // Release FIFO 0 output mailbox.
  // Make the next incoming message available.
  CAN1->RF0R |= 0x20UL;
}
 
/**
 * Encodes CAN messages using the CAN message struct and populates the
 * data registers with the sent.
 *
 * @params CAN_tx_msg - CAN message structure for transmission
 *
 */
void CANSend(CAN_msg_t* CAN_tx_msg)
{
  volatile int count = 0;

  uint32_t out = 0;
  if (CAN_tx_msg->format == EXTENDED_FORMAT) { // Extended frame format
      out = ((CAN_tx_msg->id & CAN_EXT_ID_MASK) << 3U) | STM32_CAN_TIR_IDE;
  }
  else {                                       // Standard frame format
      out = ((CAN_tx_msg->id & CAN_STD_ID_MASK) << 21U);
  }

  // Remote frame
  if (CAN_tx_msg->type == REMOTE_FRAME) {
      out |= STM32_CAN_TIR_RTR;
  }

  CAN1->sTxMailBox[0].TDTR &= ~(0xF);
  CAN1->sTxMailBox[0].TDTR |= CAN_tx_msg->len & 0xFUL;
 
  CAN1->sTxMailBox[0].TDLR  = (((uint32_t) CAN_tx_msg->data[3] << 24) |
                               ((uint32_t) CAN_tx_msg->data[2] << 16) |
                               ((uint32_t) CAN_tx_msg->data[1] <<  8) |
                               ((uint32_t) CAN_tx_msg->data[0]      ));
  CAN1->sTxMailBox[0].TDHR  = (((uint32_t) CAN_tx_msg->data[7] << 24) |
                               ((uint32_t) CAN_tx_msg->data[6] << 16) |
                               ((uint32_t) CAN_tx_msg->data[5] <<  8) |
                               ((uint32_t) CAN_tx_msg->data[4]      ));

  // Send Go
  CAN1->sTxMailBox[0].TIR = out | STM32_CAN_TIR_TXRQ;

  // Wait until the mailbox is empty
  while(CAN1->sTxMailBox[0].TIR & 0x1UL && count++ < 1000000);

  // The mailbox don't becomes empty while loop
  if (CAN1->sTxMailBox[0].TIR & 0x1UL) {
    Serial3.println("Send Fail");
    Serial3.println(CAN1->ESR);
    Serial3.println(CAN1->MSR);
    Serial3.println(CAN1->TSR);
  }
}

 /**
 * Returns whether there are CAN messages available.
 *
 * @returns If pending CAN messages are in the CAN controller
 *
 */
uint8_t CANMsgAvail(void)
{
  // Check for pending FIFO 0 messages
  return CAN1->RF0R & 0x3UL;
}


uint8_t counter = 0;
uint8_t frameLength = 0;
unsigned long previousMillis = 0;     // stores last time output was updated
const long interval = 1000;           // transmission interval (milliseconds)

void setup() {
  Serial3.begin(115200);
  //bool ret = CANInit(CAN_500KBPS, 0);  // CAN_RX mapped to PA11, CAN_TX mapped to PA12
  bool ret = CANInit(CAN_125KBPS, 2);  // CAN_RX mapped to PB8, CAN_TX mapped to PB9
  //bool ret = CANInit(CAN_1000KBPS, 0);  // CAN_RX mapped to PA11, CAN_TX mapped to PA12
  //bool ret = CANInit(CAN_1000KBPS, 2);  // CAN_RX mapped to PB8, CAN_TX mapped to PB9
  //bool ret = CANInit(CAN_1000KBPS, 3);  // CAN_RX mapped to PD0, CAN_TX mapped to PD1
  if (!ret) while(true);
}

void loop() {
  CAN_msg_t CAN_TX_msg;
  CAN_msg_t CAN_RX_msg;

  CAN_TX_msg.data[0] = 0x00;
  CAN_TX_msg.data[1] = 0x01;
  CAN_TX_msg.data[2] = 0x02;
  CAN_TX_msg.data[3] = 0x03;
  CAN_TX_msg.data[4] = 0x04;
  CAN_TX_msg.data[5] = 0x05;
  CAN_TX_msg.data[6] = 0x06;
  CAN_TX_msg.data[7] = 0x07;
  CAN_TX_msg.len = frameLength;

  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    if ( ( counter % 2) == 0) {
      CAN_TX_msg.type = DATA_FRAME;
      if (CAN_TX_msg.len == 0) CAN_TX_msg.type = REMOTE_FRAME;
      CAN_TX_msg.format = STANDARD_FORMAT;
      CAN_TX_msg.id = 0x000;
    } else {
      CAN_TX_msg.type = DATA_FRAME;
      if (CAN_TX_msg.len == 0) CAN_TX_msg.type = REMOTE_FRAME;
      CAN_TX_msg.format = STANDARD_FORMAT;
      CAN_TX_msg.id = 0x400;
    }
    CANSend(&CAN_TX_msg);
    frameLength++;
    if (frameLength == 9) frameLength = 0;
    counter++;
  }
 
  if(CANMsgAvail()) {
    CANReceive(&CAN_RX_msg);

    if (CAN_RX_msg.format == EXTENDED_FORMAT) {
      Serial3.print("Extended ID: 0x");
      if (CAN_RX_msg.id < 0x10000000) Serial3.print("0");
      if (CAN_RX_msg.id < 0x1000000) Serial3.print("00");
      if (CAN_RX_msg.id < 0x100000) Serial3.print("000");
      if (CAN_RX_msg.id < 0x10000) Serial3.print("0000");
      Serial3.print(CAN_RX_msg.id, HEX);
    } else {
      Serial3.print("Standard ID: 0x");
      if (CAN_RX_msg.id < 0x100) Serial3.print("0");
      if (CAN_RX_msg.id < 0x10) Serial3.print("00");
      Serial3.print(CAN_RX_msg.id, HEX);
      Serial3.print("     ");
    }

    Serial3.print(" DLC: ");
    Serial3.print(CAN_RX_msg.len);
    if (CAN_RX_msg.type == DATA_FRAME) {
      Serial3.print(" Data: ");
      for(int i=0; i<CAN_RX_msg.len; i++) {
        Serial3.print("0x");
        Serial3.print(CAN_RX_msg.data[i], HEX);
        if (i != (CAN_RX_msg.len-1))  Serial3.print(" ");
      }
      Serial3.println();
    } else {
      Serial3.println(" Data: REMOTE REQUEST FRAME");
    }
  }
   
 

}
« Last Edit: May 14, 2021, 02:31:56 am by poot36 »
 

Offline poot36Topic starter

  • Frequent Contributor
  • **
  • Posts: 678
  • Country: ca
I have made some progress with this code, the screen now flashes (I think it is still resetting).

Code: [Select]
uint8_t counter = 0;
uint8_t frameLength = 0;
uint8_t frameLength1 = 0;
unsigned long previousMillis = 0;     // stores last time output was updated
const long interval = 1000;           // transmission interval (milliseconds)

void setup() {
  Serial3.begin(115200);
  //bool ret = CANInit(CAN_500KBPS, 0);  // CAN_RX mapped to PA11, CAN_TX mapped to PA12
  bool ret = CANInit(CAN_125KBPS, 2);  // CAN_RX mapped to PB8, CAN_TX mapped to PB9
  //bool ret = CANInit(CAN_1000KBPS, 0);  // CAN_RX mapped to PA11, CAN_TX mapped to PA12
  //bool ret = CANInit(CAN_1000KBPS, 2);  // CAN_RX mapped to PB8, CAN_TX mapped to PB9
  //bool ret = CANInit(CAN_1000KBPS, 3);  // CAN_RX mapped to PD0, CAN_TX mapped to PD1
  if (!ret) while(true);
}

void loop() {
  CAN_msg_t CAN_TX_msg;
  CAN_msg_t CAN_TX_msg1;
  CAN_msg_t CAN_RX_msg;

  CAN_TX_msg.data[0] = 0xFD;
  CAN_TX_msg.data[1] = 0x16;
  CAN_TX_msg.data[2] = 0x3F;
  CAN_TX_msg.data[3] = 0xFF;
  CAN_TX_msg.data[4] = 0xFF;
  CAN_TX_msg.data[5] = 0xFF;
  CAN_TX_msg.data[6] = 0xFF;
  CAN_TX_msg.data[7] = 0xFF;
  CAN_TX_msg.len = frameLength;

  CAN_TX_msg1.data[0] = 0x63;
  CAN_TX_msg1.data[1] = 0x00;
  CAN_TX_msg1.data[2] = 0x00;
  CAN_TX_msg1.data[3] = 0x00;
  CAN_TX_msg1.data[4] = 0x00;
  CAN_TX_msg1.data[5] = 0x00;
  CAN_TX_msg1.len = frameLength1;

  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    if ( ( counter % 2) == 0) {
      CAN_TX_msg1.type = DATA_FRAME;
      if (CAN_TX_msg1.len == 0) CAN_TX_msg1.type = REMOTE_FRAME;
      CAN_TX_msg1.format = STANDARD_FORMAT;
      CAN_TX_msg1.id = 0x000;
    } else {
      CAN_TX_msg.type = DATA_FRAME;
      if (CAN_TX_msg.len == 0) CAN_TX_msg.type = REMOTE_FRAME;
      CAN_TX_msg.format = STANDARD_FORMAT;
      CAN_TX_msg.id = 0x415;
    }
    CANSend(&CAN_TX_msg);
    frameLength++;
    if (frameLength == 9) frameLength = 0;

    CANSend(&CAN_TX_msg1);
    frameLength1++;
    if (frameLength1 == 7) frameLength1 = 0;
    counter++;
  }

Not sure if I can do this
CAN_msg_t CAN_TX_msg;
 CAN_msg_t CAN_TX_msg1;
in the code though.
 

Offline dc101

  • Regular Contributor
  • *
  • Posts: 220
  • Country: us
I saw the forum post you linked, I just wasn't able to tell from the messages if it was related to your radio or not.

Not sure what you mean by 6 bit and 8 bit codes? Are you talking about the can bus ID or the data field or something else? https://copperhilltech.com/blog/controller-area-network-can-bus-message-frame-architecture/

There are base frames and extended frames in can bus, base frames have an 11 bit id, and extended frames have a 29 bit id. https://www.kvaser.com/about-can/the-can-protocol/can-messages-13/

The biggest issue I had when first writing code to send can bus messages with my Keil dev board was getting the format of the message correct in the various registers. It's been a few years, but I think it was an endian issue that was messing me up.
 

Offline poot36Topic starter

  • Frequent Contributor
  • **
  • Posts: 678
  • Country: ca
I think I do not understand the can protocol very well, in the screenshot it shows by the ID 000 a 6 and only 6 sections of 2 bit hex data.  That is what I am trying to send but I am not sure if the code that I have even supports that.  I had the opportunity to see what the radio was doing in the coworkers truck and it was doing the oddest things.  Sometimes it would not power up at all, some times it would just show the power up splash screen, some times it would let you in and select various options before completely locking up.  I even had it stay turned on in the absence of can data so that may explain them having a flat battery some of the time.  I also have had it where the radio would work it then froze up but the radio kept playing until you turned off the ignition but the screen was still showing the radio page with the ignition off but it looked like it was not getting updated because there was odd colored lines around most of the square boxes and some of the button text was gone.  If you turned the ignition back on the radio would keep playing.  Very odd.  I think the main CPU is having issues as the display and freezing issues most likely point to that.  I really need to get this running on the bench to be able to probe voltages and clock signals as well as reset signals in the radio.
 

Offline poot36Topic starter

  • Frequent Contributor
  • **
  • Posts: 678
  • Country: ca
Ok, so I have made some progress, the resetting with screen flashing was caused by a missing Can bus data line (clip was not making good connection).  I have fixed that and now when I send the power up code ID 0x000 data 0x63 0x00 0x00 0x00 0x00 0x00 I now get the illumination for the buttons to glow and the eject button now works.  I am still struggling with sending an additional code after this one with the code I have now.
Code: [Select]
#define DEBUG 0

//                      RX    TX
HardwareSerial Serial3(PA10, PA9);

/* Symbolic names for bit rate of CAN message                                */
typedef enum {CAN_50KBPS, CAN_100KBPS, CAN_125KBPS, CAN_250KBPS, CAN_500KBPS, CAN_1000KBPS} BITRATE;

/* Symbolic names for formats of CAN message                                 */
typedef enum {STANDARD_FORMAT = 0, EXTENDED_FORMAT} CAN_FORMAT;

/* Symbolic names for type of CAN message                                    */
typedef enum {DATA_FRAME = 0, REMOTE_FRAME}         CAN_FRAME;


typedef struct
{
  uint32_t id;        /* 29 bit identifier                               */
  uint8_t  data[8];   /* Data field                                      */
  uint8_t  len;       /* Length of data field in bytes                   */
  uint8_t  ch;        /* Object channel(Not use)                         */
  uint8_t  format;    /* 0 - STANDARD, 1- EXTENDED IDENTIFIER            */
  uint8_t  type;      /* 0 - DATA FRAME, 1 - REMOTE FRAME                */
} CAN_msg_t;

typedef const struct
{
  uint8_t TS2;
  uint8_t TS1;
  uint8_t BRP;
} CAN_bit_timing_config_t;

CAN_bit_timing_config_t can_configs[6] = {{2, 13, 45}, {2, 15, 20}, {2, 13, 18}, {2, 13, 9}, {2, 15, 4}, {2, 15, 2}};

/**
 * Print registers.
*/
void printRegister(char * buf, uint32_t reg) {
  if (DEBUG == 0) return;
  Serial3.print(buf);
  Serial3.print(reg, HEX);
  Serial3.println();
}

/**
 * Initializes the CAN filter registers.
 *
 * @preconditions   - This register can be written only when the filter initialization mode is set (FINIT=1) in the CAN_FMR register.
 * @params: index   - Specified filter index. index 27:14 are available in connectivity line devices only.
 * @params: scale   - Select filter scale.
 *                    0: Dual 16-bit scale configuration
 *                    1: Single 32-bit scale configuration
 * @params: mode    - Select filter mode.
 *                    0: Two 32-bit registers of filter bank x are in Identifier Mask mode
 *                    1: Two 32-bit registers of filter bank x are in Identifier List mode
 * @params: fifo    - Select filter assigned.
 *                    0: Filter assigned to FIFO 0
 *                    1: Filter assigned to FIFO 1
 * @params: bank1   - Filter bank register 1
 * @params: bank2   - Filter bank register 2
 *
 */
void CANSetFilter(uint8_t index, uint8_t scale, uint8_t mode, uint8_t fifo, uint32_t bank1, uint32_t bank2) {
  if (index > 27) return;

  CAN1->FA1R &= ~(0x1UL<<index);               // Deactivate filter

  if (scale == 0) {
    CAN1->FS1R &= ~(0x1UL<<index);             // Set filter to Dual 16-bit scale configuration
  } else {
    CAN1->FS1R |= (0x1UL<<index);              // Set filter to single 32 bit configuration
  }
    if (mode == 0) {
    CAN1->FM1R &= ~(0x1UL<<index);             // Set filter to Mask mode
  } else {
    CAN1->FM1R |= (0x1UL<<index);              // Set filter to List mode
  }

  if (fifo == 0) {
    CAN1->FFA1R &= ~(0x1UL<<index);            // Set filter assigned to FIFO 0
  } else {
    CAN1->FFA1R |= (0x1UL<<index);             // Set filter assigned to FIFO 1
  }

  CAN1->sFilterRegister[index].FR1 = bank1;    // Set filter bank registers1
  CAN1->sFilterRegister[index].FR2 = bank2;    // Set filter bank registers2

  CAN1->FA1R |= (0x1UL<<index);                // Activate filter

}

/**
 * Initializes the CAN controller with specified bit rate.
 *
 * @params: bitrate - Specified bitrate. If this value is not one of the defined constants, bit rate will be defaulted to 125KBS
 * @params: remap   - Select CAN port.
 *                    =0:CAN_RX mapped to PA11, CAN_TX mapped to PA12
 *                    =1:Not used
 *                    =2:CAN_RX mapped to PB8, CAN_TX mapped to PB9 (not available on 36-pin package)
 *                    =3:CAN_RX mapped to PD0, CAN_TX mapped to PD1 (available on 100-pin and 144-pin package)
 *
 */
bool CANInit(BITRATE bitrate, int remap)
{
  // Reference manual
  // [url]https://www.st.com/content/ccc/resource/technical/document/reference_manual/59/b9/ba/7f/11/af/43/d5/CD00171190.pdf/files/CD00171190.pdf/jcr:content/translations/en.CD00171190.pdf[/url]

  RCC->APB1ENR |= 0x2000000UL;       // Enable CAN clock
  RCC->APB2ENR |= 0x1UL;             // Enable AFIO clock
  AFIO->MAPR   &= 0xFFFF9FFF;        // reset CAN remap
                                     // CAN_RX mapped to PA11, CAN_TX mapped to PA12

  if (remap == 0) {
    RCC->APB2ENR |= 0x4UL;           // Enable GPIOA clock
    GPIOA->CRH   &= ~(0xFF000UL);    // Configure PA12(0b0000) and PA11(0b0000)
                                     // 0b0000
                                     //   MODE=00(Input mode)
                                     //   CNF=00(Analog mode)

    GPIOA->CRH   |= 0xB8FFFUL;       // Configure PA12(0b1011) and PA11(0b1000)
                                     // 0b1011
                                     //   MODE=11(Output mode, max speed 50 MHz)
                                     //   CNF=10(Alternate function output Push-pull
                                     // 0b1000
                                     //   MODE=00(Input mode)
                                     //   CNF=10(Input with pull-up / pull-down)
                                     
    GPIOA->ODR |= 0x1UL << 12;       // PA12 Upll-up
   
  }
                               
  if (remap == 2) {
    AFIO->MAPR   |= 0x00004000;      // set CAN remap
                                     // CAN_RX mapped to PB8, CAN_TX mapped to PB9 (not available on 36-pin package)

    RCC->APB2ENR |= 0x8UL;           // Enable GPIOB clock
    GPIOB->CRH   &= ~(0xFFUL);       // Configure PB9(0b0000) and PB8(0b0000)
                                     // 0b0000
                                     //   MODE=00(Input mode)
                                     //   CNF=00(Analog mode)

    GPIOB->CRH   |= 0xB8UL;          // Configure PB9(0b1011) and PB8(0b1000)
                                     // 0b1011
                                     //   MODE=11(Output mode, max speed 50 MHz)
                                     //   CNF=10(Alternate function output Push-pull
                                     // 0b1000
                                     //   MODE=00(Input mode)
                                     //   CNF=10(Input with pull-up / pull-down)
                                     
    GPIOB->ODR |= 0x1UL << 8;        // PB8 Upll-up
  }
 
  if (remap == 3) {
    AFIO->MAPR   |= 0x00005000;      // set CAN remap
                                     // CAN_RX mapped to PD0, CAN_TX mapped to PD1 (available on 100-pin and 144-pin package)

    RCC->APB2ENR |= 0x20UL;          // Enable GPIOD clock
    GPIOD->CRL   &= ~(0xFFUL);       // Configure PD1(0b0000) and PD0(0b0000)
                                     // 0b0000
                                     //   MODE=00(Input mode)
                                     //   CNF=00(Analog mode)

    GPIOD->CRH   |= 0xB8UL;          // Configure PD1(0b1011) and PD0(0b1000)
                                     // 0b1000
                                     //   MODE=00(Input mode)
                                     //   CNF=10(Input with pull-up / pull-down)
                                     // 0b1011
                                     //   MODE=11(Output mode, max speed 50 MHz)
                                     //   CNF=10(Alternate function output Push-pull
                                     
    GPIOD->ODR |= 0x1UL << 0;        // PD0 Upll-up
  }

  CAN1->MCR |= 0x1UL;                   // Require CAN1 to Initialization mode
  while (!(CAN1->MSR & 0x1UL));         // Wait for Initialization mode

  //CAN1->MCR = 0x51UL;                 // Hardware initialization(No automatic retransmission)
  CAN1->MCR = 0x41UL;                   // Hardware initialization(With automatic retransmission)
   
  // Set bit rates
  CAN1->BTR &= ~(((0x03) << 24) | ((0x07) << 20) | ((0x0F) << 16) | (0x1FF));
  CAN1->BTR |=  (((can_configs[bitrate].TS2-1) & 0x07) << 20) | (((can_configs[bitrate].TS1-1) & 0x0F) << 16) | ((can_configs[bitrate].BRP-1) & 0x1FF);

  // Configure Filters to default values
  CAN1->FMR  |=   0x1UL;                // Set to filter initialization mode
  CAN1->FMR  &= 0xFFFFC0FF;             // Clear CAN2 start bank

  // bxCAN has 28 filters.
  // These filters are used for both CAN1 and CAN2.
  // STM32F103 has only CAN1, so all 28 are used for CAN1
  CAN1->FMR  |= 0x1C << 8;              // Assign all filters to CAN1

  // Set fileter 0
  // Single 32-bit scale configuration
  // Two 32-bit registers of filter bank x are in Identifier Mask mode
  // Filter assigned to FIFO 0
  // Filter bank register to all 0
  CANSetFilter(0, 1, 0, 0, 0x0UL, 0x0UL);
 
  CAN1->FMR   &= ~(0x1UL);              // Deactivate initialization mode

  uint16_t TimeoutMilliseconds = 1000;
  bool can1 = false;
  CAN1->MCR   &= ~(0x1UL);              // Require CAN1 to normal mode

  // Wait for normal mode
  // If the connection is not correct, it will not return to normal mode.
  for (uint16_t wait_ack = 0; wait_ack < TimeoutMilliseconds; wait_ack++) {
    if ((CAN1->MSR & 0x1UL) == 0) {
      can1 = true;
      break;
    }
    delayMicroseconds(1000);
  }
  //Serial3.print("can1=");
  //Serial3.println(can1);
  if (can1) {
    Serial3.println("CAN1 initialize ok");
  } else {
    Serial3.println("CAN1 initialize fail!!");
    return false;
  }
  return true;
}


#define STM32_CAN_TIR_TXRQ              (1U << 0U)  // Bit 0: Transmit Mailbox Request
#define STM32_CAN_RIR_RTR               (1U << 1U)  // Bit 1: Remote Transmission Request
#define STM32_CAN_RIR_IDE               (1U << 2U)  // Bit 2: Identifier Extension
#define STM32_CAN_TIR_RTR               (1U << 1U)  // Bit 1: Remote Transmission Request
#define STM32_CAN_TIR_IDE               (1U << 2U)  // Bit 2: Identifier Extension

#define CAN_EXT_ID_MASK                 0x1FFFFFFFU
#define CAN_STD_ID_MASK                 0x000007FFU
 
/**
 * Decodes CAN messages from the data registers and populates a
 * CAN message struct with the data fields.
 *
 * @preconditions A valid CAN message is received
 * @params CAN_rx_msg - CAN message structure for reception
 *
 */
void CANReceive(CAN_msg_t* CAN_rx_msg)
{
  uint32_t id = CAN1->sFIFOMailBox[0].RIR;
  if ((id & STM32_CAN_RIR_IDE) == 0) { // Standard frame format
      CAN_rx_msg->format = STANDARD_FORMAT;;
      CAN_rx_msg->id = (CAN_STD_ID_MASK & (id >> 21U));
  }
  else {                               // Extended frame format
      CAN_rx_msg->format = EXTENDED_FORMAT;;
      CAN_rx_msg->id = (CAN_EXT_ID_MASK & (id >> 3U));
  }

  if ((id & STM32_CAN_RIR_RTR) == 0) { // Data frame
      CAN_rx_msg->type = DATA_FRAME;
  }
  else {                               // Remote frame
      CAN_rx_msg->type = REMOTE_FRAME;
  }

 
  CAN_rx_msg->len = (CAN1->sFIFOMailBox[0].RDTR) & 0xFUL;
 
  CAN_rx_msg->data[0] = 0xFFUL &  CAN1->sFIFOMailBox[0].RDLR;
  CAN_rx_msg->data[1] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDLR >> 8);
  CAN_rx_msg->data[2] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDLR >> 16);
  CAN_rx_msg->data[3] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDLR >> 24);
  CAN_rx_msg->data[4] = 0xFFUL &  CAN1->sFIFOMailBox[0].RDHR;
  CAN_rx_msg->data[5] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDHR >> 8);
  CAN_rx_msg->data[6] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDHR >> 16);
  CAN_rx_msg->data[7] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDHR >> 24);

  // Release FIFO 0 output mailbox.
  // Make the next incoming message available.
  CAN1->RF0R |= 0x20UL;
}
 
/**
 * Encodes CAN messages using the CAN message struct and populates the
 * data registers with the sent.
 *
 * @params CAN_tx_msg - CAN message structure for transmission
 *
 */
void CANSend(CAN_msg_t* CAN_tx_msg)
{
  volatile int count = 0;

  uint32_t out = 0;
  if (CAN_tx_msg->format == EXTENDED_FORMAT) { // Extended frame format
      out = ((CAN_tx_msg->id & CAN_EXT_ID_MASK) << 3U) | STM32_CAN_TIR_IDE;
  }
  else {                                       // Standard frame format
      out = ((CAN_tx_msg->id & CAN_STD_ID_MASK) << 21U);
  }

  // Remote frame
  if (CAN_tx_msg->type == REMOTE_FRAME) {
      out |= STM32_CAN_TIR_RTR;
  }

  CAN1->sTxMailBox[0].TDTR &= ~(0xF);
  CAN1->sTxMailBox[0].TDTR |= CAN_tx_msg->len & 0xFUL;
 
  CAN1->sTxMailBox[0].TDLR  = (((uint32_t) CAN_tx_msg->data[3] << 24) |
                               ((uint32_t) CAN_tx_msg->data[2] << 16) |
                               ((uint32_t) CAN_tx_msg->data[1] <<  8) |
                               ((uint32_t) CAN_tx_msg->data[0]      ));
  CAN1->sTxMailBox[0].TDHR  = (((uint32_t) CAN_tx_msg->data[7] << 24) |
                               ((uint32_t) CAN_tx_msg->data[6] << 16) |
                               ((uint32_t) CAN_tx_msg->data[5] <<  8) |
                               ((uint32_t) CAN_tx_msg->data[4]      ));

  // Send Go
  CAN1->sTxMailBox[0].TIR = out | STM32_CAN_TIR_TXRQ;

  // Wait until the mailbox is empty
  while(CAN1->sTxMailBox[0].TIR & 0x1UL && count++ < 1000000);

  // The mailbox don't becomes empty while loop
  if (CAN1->sTxMailBox[0].TIR & 0x1UL) {
    Serial3.println("Send Fail");
    Serial3.println(CAN1->ESR);
    Serial3.println(CAN1->MSR);
    Serial3.println(CAN1->TSR);
  }
}

 /**
 * Returns whether there are CAN messages available.
 *
 * @returns If pending CAN messages are in the CAN controller
 *
 */
uint8_t CANMsgAvail(void)
{
  // Check for pending FIFO 0 messages
  return CAN1->RF0R & 0x3UL;
}


uint8_t counter = 0;
uint8_t counter1 = 0;
uint8_t frameLength = 0;
uint8_t frameLength1 = 0;
unsigned long previousMillis = 0;     // stores last time output was updated
unsigned long previousMillis1 = 0;
const long interval = 200;           // transmission interval (milliseconds)
const long interval1 = 200;

void setup() {
  Serial3.begin(115200);
  //bool ret = CANInit(CAN_500KBPS, 0);  // CAN_RX mapped to PA11, CAN_TX mapped to PA12
  bool ret = CANInit(CAN_125KBPS, 2);  // CAN_RX mapped to PB8, CAN_TX mapped to PB9
  //bool ret = CANInit(CAN_1000KBPS, 0);  // CAN_RX mapped to PA11, CAN_TX mapped to PA12
  //bool ret = CANInit(CAN_1000KBPS, 2);  // CAN_RX mapped to PB8, CAN_TX mapped to PB9
  //bool ret = CANInit(CAN_1000KBPS, 3);  // CAN_RX mapped to PD0, CAN_TX mapped to PD1
  if (!ret) while(true);
}

void loop() {
 
  CAN_msg_t CAN_TX_msg1;
  CAN_msg_t CAN_RX_msg;
 
  CAN_TX_msg1.data[0] = 0x63;
  CAN_TX_msg1.data[1] = 0x00;
  CAN_TX_msg1.data[2] = 0x00;
  CAN_TX_msg1.data[3] = 0x00;
  CAN_TX_msg1.data[4] = 0x00;
  CAN_TX_msg1.data[5] = 0x00;
  CAN_TX_msg1.len = frameLength1;

  unsigned long currentMillis1 = millis();
  if (currentMillis1 - previousMillis1 >= interval1) {
    previousMillis1 = currentMillis1;
    if ( ( counter1 % 2) == 0) {
      CAN_TX_msg1.type = DATA_FRAME;
      if (CAN_TX_msg1.len == 0) CAN_TX_msg1.type = REMOTE_FRAME;
      CAN_TX_msg1.format = STANDARD_FORMAT;
      CAN_TX_msg1.id = 0x000;
    }
    CANSend(&CAN_TX_msg1);
    frameLength1++;
    if (frameLength1 == 7) frameLength1 = 0;
    counter1++;
  }

  CAN_msg_t CAN_TX_msg;

  CAN_TX_msg.data[0] = 0xFD;
  CAN_TX_msg.data[1] = 0x16;
  CAN_TX_msg.data[2] = 0x3F;
  CAN_TX_msg.data[3] = 0xFF;
  CAN_TX_msg.data[4] = 0xFF;
  CAN_TX_msg.data[5] = 0xFF;
  CAN_TX_msg.data[6] = 0xFF;
  CAN_TX_msg.data[7] = 0xFF;
  CAN_TX_msg.len = frameLength;

  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    if ( ( counter % 2) == 0) {
      CAN_TX_msg.type = DATA_FRAME;
      if (CAN_TX_msg.len == 0) CAN_TX_msg.type = REMOTE_FRAME;
      CAN_TX_msg.format = STANDARD_FORMAT;
      CAN_TX_msg.id = 0x415;
    }
    //CANSend(&CAN_TX_msg);
    frameLength++;
    if (frameLength == 9) frameLength = 0;
    counter++;
  }
 
  if(CANMsgAvail()) {
    CANReceive(&CAN_RX_msg);

    if (CAN_RX_msg.format == EXTENDED_FORMAT) {
      Serial3.print("Extended ID: 0x");
      if (CAN_RX_msg.id < 0x10000000) Serial3.print("0");
      if (CAN_RX_msg.id < 0x1000000) Serial3.print("00");
      if (CAN_RX_msg.id < 0x100000) Serial3.print("000");
      if (CAN_RX_msg.id < 0x10000) Serial3.print("0000");
      Serial3.print(CAN_RX_msg.id, HEX);
    } else {
      Serial3.print("Standard ID: 0x");
      if (CAN_RX_msg.id < 0x100) Serial3.print("0");
      if (CAN_RX_msg.id < 0x10) Serial3.print("00");
      Serial3.print(CAN_RX_msg.id, HEX);
      Serial3.print("     ");
    }

    Serial3.print(" DLC: ");
    Serial3.print(CAN_RX_msg.len);
    if (CAN_RX_msg.type == DATA_FRAME) {
      Serial3.print(" Data: ");
      for(int i=0; i<CAN_RX_msg.len; i++) {
        Serial3.print("0x");
        Serial3.print(CAN_RX_msg.data[i], HEX);
        if (i != (CAN_RX_msg.len-1))  Serial3.print(" ");
      }
      Serial3.println();
    } else {
      Serial3.println(" Data: REMOTE REQUEST FRAME");
    }
  }
   
 

}


I can change between sending the power on code and the radio ID code ID 0x415 data 0xFD 0x16 0x3F 0xFF 0xFF 0xFF 0xFF 0xFF by commenting out either the CANSend(&CAN_TX_msg1); or the CANSend(&CAN_TX_msg); lines.  I have found that if I first run it with the power on code and then reprogram it with the radio ID code I have been able to get the boot logo to appear when I press the eject button but it then goes away.  My issue is getting it to send both codes in sequence with the correct timing between them.  If I just send the power on code I can get the eject button to work and the buttons to illuminate but no display and if I just send the radio ID code nothing happens but the current consumption goes to around 2 Amps so it is sort of powered up (around this much current is also drawn with the power up code as well).  Got any ideas why I can not get this code to send 2 Can bus codes in sequence?  I really suck at programming and am mostly a hardware person.
 

Offline YetAnotherTechie

  • Regular Contributor
  • *
  • Posts: 221
  • Country: pt
How long have you spent on this?? As i understood, you're not doing it for fun, part of managing a repair is knowing when to say "no". Is your coworker going to pay you for 30hours of work? isn't he upset about not having the radio?
 

Offline SilverSolder

  • Super Contributor
  • ***
  • Posts: 6126
  • Country: 00

Got to love modern technology, even turning on a radio has been turned into a crazy project lol

The average cost of a new car in the US is now north of $38K, and this is the kind of stuff you get for your money!
 

Offline poot36Topic starter

  • Frequent Contributor
  • **
  • Posts: 678
  • Country: ca
@YetAnotherTechie I don't really know how much time I have spent on this.  It is a learning experience and well it is not exactly for fun I am having fun learning.  I am not in it for the money and the radio has never worked correctly since they got the truck used so they are not missing it.

@SilverSolder As far as I can tell they have been doing this since around 2005 or so where the Can bus is used to power up the radio.  Not easy to trouble shoot is correct.  If I can get this figured out then anyone with a STM32 blue pill and a compatible Can bus transceiver chip can make this work without having to spend $30 or more on custom made devices to do the same job as at most $10 worth of parts.
 

Offline poot36Topic starter

  • Frequent Contributor
  • **
  • Posts: 678
  • Country: ca
Been doing some more testing and have found that the RXD pin (this one sends data into the radio) on the TJA1041A Can bus transceiver chip (datasheet: https://www.nxp.com/docs/en/data-sheet/TJA1041A.pdf ) in the radio matches the data sent by the RX pin on the STM32 micro for the most part how ever the TXD pin on radio and the TX pin on the STM32 do not match very frequently.  Not sure if this is an issue or not.  I have also had the radio power up fully for a few seconds when just sending the Power on command without the Radio ID command although this could be due to my crappy alligator chips briefly loosing connection and some other corrupted data being sent to the unit.  I also probed the INH pin on the TJA1041A chip and found that it occasionally goes low disabling all the power supplies in the radio although this could be because I am not sending the Radio ID command and it is rebooting because of that.  Also have noticed that most of the big processing chips in the unit run around 70C or more, is that normal?  Do you think I could get the code to send the 2 codes I need by placing them in individual functions and calling them from the loop section in the code?  Kind of like this code I found online? https://github.com/alex3dbros/LGH1ScooterPackPower/blob/master/Jump_Start.ino
« Last Edit: May 24, 2021, 11:51:23 pm by poot36 »
 

Offline poot36Topic starter

  • Frequent Contributor
  • **
  • Posts: 678
  • Country: ca
Here is the latest code that will turn on the illumination but nothing else.  It should be sending the Radio ID code as well but I am unable to confirm that.  I have found that the radio is way more likely to power up with the illumination if I power it up after I power on the STM32 board.

Code: [Select]
#define DEBUG 0

//                      RX    TX
HardwareSerial Serial3(PA10, PA9);

/* Symbolic names for bit rate of CAN message                                */
typedef enum {CAN_50KBPS, CAN_100KBPS, CAN_125KBPS, CAN_250KBPS, CAN_500KBPS, CAN_1000KBPS} BITRATE;

/* Symbolic names for formats of CAN message                                 */
typedef enum {STANDARD_FORMAT = 0, EXTENDED_FORMAT} CAN_FORMAT;

/* Symbolic names for type of CAN message                                    */
typedef enum {DATA_FRAME = 0, REMOTE_FRAME}         CAN_FRAME;


typedef struct
{
  uint32_t id;        /* 29 bit identifier                               */
  uint8_t  data[8];   /* Data field                                      */
  uint8_t  len;       /* Length of data field in bytes                   */
  uint8_t  ch;        /* Object channel(Not use)                         */
  uint8_t  format;    /* 0 - STANDARD, 1- EXTENDED IDENTIFIER            */
  uint8_t  type;      /* 0 - DATA FRAME, 1 - REMOTE FRAME                */
} CAN_msg_t;

typedef const struct
{
  uint8_t TS2;
  uint8_t TS1;
  uint8_t BRP;
} CAN_bit_timing_config_t;

CAN_bit_timing_config_t can_configs[6] = {{2, 13, 45}, {2, 15, 20}, {2, 13, 18}, {2, 13, 9}, {2, 15, 4}, {2, 15, 2}};

/**
 * Print registers.
*/
void printRegister(char * buf, uint32_t reg) {
  if (DEBUG == 0) return;
  Serial3.print(buf);
  Serial3.print(reg, HEX);
  Serial3.println();
}

/**
 * Initializes the CAN filter registers.
 *
 * @preconditions   - This register can be written only when the filter initialization mode is set (FINIT=1) in the CAN_FMR register.
 * @params: index   - Specified filter index. index 27:14 are available in connectivity line devices only.
 * @params: scale   - Select filter scale.
 *                    0: Dual 16-bit scale configuration
 *                    1: Single 32-bit scale configuration
 * @params: mode    - Select filter mode.
 *                    0: Two 32-bit registers of filter bank x are in Identifier Mask mode
 *                    1: Two 32-bit registers of filter bank x are in Identifier List mode
 * @params: fifo    - Select filter assigned.
 *                    0: Filter assigned to FIFO 0
 *                    1: Filter assigned to FIFO 1
 * @params: bank1   - Filter bank register 1
 * @params: bank2   - Filter bank register 2
 *
 */
void CANSetFilter(uint8_t index, uint8_t scale, uint8_t mode, uint8_t fifo, uint32_t bank1, uint32_t bank2) {
  if (index > 27) return;

  CAN1->FA1R &= ~(0x1UL<<index);               // Deactivate filter

  if (scale == 0) {
    CAN1->FS1R &= ~(0x1UL<<index);             // Set filter to Dual 16-bit scale configuration
  } else {
    CAN1->FS1R |= (0x1UL<<index);              // Set filter to single 32 bit configuration
  }
    if (mode == 0) {
    CAN1->FM1R &= ~(0x1UL<<index);             // Set filter to Mask mode
  } else {
    CAN1->FM1R |= (0x1UL<<index);              // Set filter to List mode
  }

  if (fifo == 0) {
    CAN1->FFA1R &= ~(0x1UL<<index);            // Set filter assigned to FIFO 0
  } else {
    CAN1->FFA1R |= (0x1UL<<index);             // Set filter assigned to FIFO 1
  }

  CAN1->sFilterRegister[index].FR1 = bank1;    // Set filter bank registers1
  CAN1->sFilterRegister[index].FR2 = bank2;    // Set filter bank registers2

  CAN1->FA1R |= (0x1UL<<index);                // Activate filter

}

/**
 * Initializes the CAN controller with specified bit rate.
 *
 * @params: bitrate - Specified bitrate. If this value is not one of the defined constants, bit rate will be defaulted to 125KBS
 * @params: remap   - Select CAN port.
 *                    =0:CAN_RX mapped to PA11, CAN_TX mapped to PA12
 *                    =1:Not used
 *                    =2:CAN_RX mapped to PB8, CAN_TX mapped to PB9 (not available on 36-pin package)
 *                    =3:CAN_RX mapped to PD0, CAN_TX mapped to PD1 (available on 100-pin and 144-pin package)
 *
 */
bool CANInit(BITRATE bitrate, int remap)
{
  // Reference manual
  // [url]https://www.st.com/content/ccc/resource/technical/document/reference_manual/59/b9/ba/7f/11/af/43/d5/CD00171190.pdf/files/CD00171190.pdf/jcr:content/translations/en.CD00171190.pdf[/url]

  RCC->APB1ENR |= 0x2000000UL;       // Enable CAN clock
  RCC->APB2ENR |= 0x1UL;             // Enable AFIO clock
  AFIO->MAPR   &= 0xFFFF9FFF;        // reset CAN remap
                                     // CAN_RX mapped to PA11, CAN_TX mapped to PA12

  if (remap == 0) {
    RCC->APB2ENR |= 0x4UL;           // Enable GPIOA clock
    GPIOA->CRH   &= ~(0xFF000UL);    // Configure PA12(0b0000) and PA11(0b0000)
                                     // 0b0000
                                     //   MODE=00(Input mode)
                                     //   CNF=00(Analog mode)

    GPIOA->CRH   |= 0xB8FFFUL;       // Configure PA12(0b1011) and PA11(0b1000)
                                     // 0b1011
                                     //   MODE=11(Output mode, max speed 50 MHz)
                                     //   CNF=10(Alternate function output Push-pull
                                     // 0b1000
                                     //   MODE=00(Input mode)
                                     //   CNF=10(Input with pull-up / pull-down)
                                     
    GPIOA->ODR |= 0x1UL << 12;       // PA12 Upll-up
   
  }
                               
  if (remap == 2) {
    AFIO->MAPR   |= 0x00004000;      // set CAN remap
                                     // CAN_RX mapped to PB8, CAN_TX mapped to PB9 (not available on 36-pin package)

    RCC->APB2ENR |= 0x8UL;           // Enable GPIOB clock
    GPIOB->CRH   &= ~(0xFFUL);       // Configure PB9(0b0000) and PB8(0b0000)
                                     // 0b0000
                                     //   MODE=00(Input mode)
                                     //   CNF=00(Analog mode)

    GPIOB->CRH   |= 0xB8UL;          // Configure PB9(0b1011) and PB8(0b1000)
                                     // 0b1011
                                     //   MODE=11(Output mode, max speed 50 MHz)
                                     //   CNF=10(Alternate function output Push-pull
                                     // 0b1000
                                     //   MODE=00(Input mode)
                                     //   CNF=10(Input with pull-up / pull-down)
                                     
    GPIOB->ODR |= 0x1UL << 8;        // PB8 Upll-up
  }
 
  if (remap == 3) {
    AFIO->MAPR   |= 0x00005000;      // set CAN remap
                                     // CAN_RX mapped to PD0, CAN_TX mapped to PD1 (available on 100-pin and 144-pin package)

    RCC->APB2ENR |= 0x20UL;          // Enable GPIOD clock
    GPIOD->CRL   &= ~(0xFFUL);       // Configure PD1(0b0000) and PD0(0b0000)
                                     // 0b0000
                                     //   MODE=00(Input mode)
                                     //   CNF=00(Analog mode)

    GPIOD->CRH   |= 0xB8UL;          // Configure PD1(0b1011) and PD0(0b1000)
                                     // 0b1000
                                     //   MODE=00(Input mode)
                                     //   CNF=10(Input with pull-up / pull-down)
                                     // 0b1011
                                     //   MODE=11(Output mode, max speed 50 MHz)
                                     //   CNF=10(Alternate function output Push-pull
                                     
    GPIOD->ODR |= 0x1UL << 0;        // PD0 Upll-up
  }

  CAN1->MCR |= 0x1UL;                   // Require CAN1 to Initialization mode
  while (!(CAN1->MSR & 0x1UL));         // Wait for Initialization mode

  //CAN1->MCR = 0x51UL;                 // Hardware initialization(No automatic retransmission)
  CAN1->MCR = 0x41UL;                   // Hardware initialization(With automatic retransmission)
   
  // Set bit rates
  CAN1->BTR &= ~(((0x03) << 24) | ((0x07) << 20) | ((0x0F) << 16) | (0x1FF));
  CAN1->BTR |=  (((can_configs[bitrate].TS2-1) & 0x07) << 20) | (((can_configs[bitrate].TS1-1) & 0x0F) << 16) | ((can_configs[bitrate].BRP-1) & 0x1FF);

  // Configure Filters to default values
  CAN1->FMR  |=   0x1UL;                // Set to filter initialization mode
  CAN1->FMR  &= 0xFFFFC0FF;             // Clear CAN2 start bank

  // bxCAN has 28 filters.
  // These filters are used for both CAN1 and CAN2.
  // STM32F103 has only CAN1, so all 28 are used for CAN1
  CAN1->FMR  |= 0x1C << 8;              // Assign all filters to CAN1

  // Set fileter 0
  // Single 32-bit scale configuration
  // Two 32-bit registers of filter bank x are in Identifier Mask mode
  // Filter assigned to FIFO 0
  // Filter bank register to all 0
  CANSetFilter(0, 1, 0, 0, 0x0UL, 0x0UL);
 
  CAN1->FMR   &= ~(0x1UL);              // Deactivate initialization mode

  uint16_t TimeoutMilliseconds = 1000;
  bool can1 = false;
  CAN1->MCR   &= ~(0x1UL);              // Require CAN1 to normal mode

  // Wait for normal mode
  // If the connection is not correct, it will not return to normal mode.
  for (uint16_t wait_ack = 0; wait_ack < TimeoutMilliseconds; wait_ack++) {
    if ((CAN1->MSR & 0x1UL) == 0) {
      can1 = true;
      break;
    }
    delayMicroseconds(1000);
  }
  //Serial3.print("can1=");
  //Serial3.println(can1);
  if (can1) {
    Serial3.println("CAN1 initialize ok");
  } else {
    Serial3.println("CAN1 initialize fail!!");
    return false;
  }
  return true;
}


#define STM32_CAN_TIR_TXRQ              (1U << 0U)  // Bit 0: Transmit Mailbox Request
#define STM32_CAN_RIR_RTR               (1U << 1U)  // Bit 1: Remote Transmission Request
#define STM32_CAN_RIR_IDE               (1U << 2U)  // Bit 2: Identifier Extension
#define STM32_CAN_TIR_RTR               (1U << 1U)  // Bit 1: Remote Transmission Request
#define STM32_CAN_TIR_IDE               (1U << 2U)  // Bit 2: Identifier Extension

#define CAN_EXT_ID_MASK                 0x1FFFFFFFU
#define CAN_STD_ID_MASK                 0x000007FFU
 
/**
 * Decodes CAN messages from the data registers and populates a
 * CAN message struct with the data fields.
 *
 * @preconditions A valid CAN message is received
 * @params CAN_rx_msg - CAN message structure for reception
 *
 */
void CANReceive(CAN_msg_t* CAN_rx_msg)
{
  uint32_t id = CAN1->sFIFOMailBox[0].RIR;
  if ((id & STM32_CAN_RIR_IDE) == 0) { // Standard frame format
      CAN_rx_msg->format = STANDARD_FORMAT;;
      CAN_rx_msg->id = (CAN_STD_ID_MASK & (id >> 21U));
  }
  else {                               // Extended frame format
      CAN_rx_msg->format = EXTENDED_FORMAT;;
      CAN_rx_msg->id = (CAN_EXT_ID_MASK & (id >> 3U));
  }

  if ((id & STM32_CAN_RIR_RTR) == 0) { // Data frame
      CAN_rx_msg->type = DATA_FRAME;
  }
  else {                               // Remote frame
      CAN_rx_msg->type = REMOTE_FRAME;
  }

 
  CAN_rx_msg->len = (CAN1->sFIFOMailBox[0].RDTR) & 0xFUL;
 
  CAN_rx_msg->data[0] = 0xFFUL &  CAN1->sFIFOMailBox[0].RDLR;
  CAN_rx_msg->data[1] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDLR >> 8);
  CAN_rx_msg->data[2] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDLR >> 16);
  CAN_rx_msg->data[3] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDLR >> 24);
  CAN_rx_msg->data[4] = 0xFFUL &  CAN1->sFIFOMailBox[0].RDHR;
  CAN_rx_msg->data[5] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDHR >> 8);
  CAN_rx_msg->data[6] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDHR >> 16);
  CAN_rx_msg->data[7] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDHR >> 24);

  // Release FIFO 0 output mailbox.
  // Make the next incoming message available.
  CAN1->RF0R |= 0x20UL;
}
 
/**
 * Encodes CAN messages using the CAN message struct and populates the
 * data registers with the sent.
 *
 * @params CAN_tx_msg - CAN message structure for transmission
 *
 */
void CANSend(CAN_msg_t* CAN_tx_msg)
{
  volatile int count = 0;

  uint32_t out = 0;
  if (CAN_tx_msg->format == EXTENDED_FORMAT) { // Extended frame format
      out = ((CAN_tx_msg->id & CAN_EXT_ID_MASK) << 3U) | STM32_CAN_TIR_IDE;
  }
  else {                                       // Standard frame format
      out = ((CAN_tx_msg->id & CAN_STD_ID_MASK) << 21U);
  }

  // Remote frame
  if (CAN_tx_msg->type == REMOTE_FRAME) {
      out |= STM32_CAN_TIR_RTR;
  }

  CAN1->sTxMailBox[0].TDTR &= ~(0xF);
  CAN1->sTxMailBox[0].TDTR |= CAN_tx_msg->len & 0xFUL;
 
  CAN1->sTxMailBox[0].TDLR  = (((uint32_t) CAN_tx_msg->data[3] << 24) |
                               ((uint32_t) CAN_tx_msg->data[2] << 16) |
                               ((uint32_t) CAN_tx_msg->data[1] <<  8) |
                               ((uint32_t) CAN_tx_msg->data[0]      ));
  CAN1->sTxMailBox[0].TDHR  = (((uint32_t) CAN_tx_msg->data[7] << 24) |
                               ((uint32_t) CAN_tx_msg->data[6] << 16) |
                               ((uint32_t) CAN_tx_msg->data[5] <<  8) |
                               ((uint32_t) CAN_tx_msg->data[4]      ));

  // Send Go
  CAN1->sTxMailBox[0].TIR = out | STM32_CAN_TIR_TXRQ;

  // Wait until the mailbox is empty
  while(CAN1->sTxMailBox[0].TIR & 0x1UL && count++ < 1000000);

  // The mailbox don't becomes empty while loop
  if (CAN1->sTxMailBox[0].TIR & 0x1UL) {
    Serial3.println("Send Fail");
    Serial3.println(CAN1->ESR);
    Serial3.println(CAN1->MSR);
    Serial3.println(CAN1->TSR);
  }
}

 /**
 * Returns whether there are CAN messages available.
 *
 * @returns If pending CAN messages are in the CAN controller
 *
 */
uint8_t CANMsgAvail(void)
{
  // Check for pending FIFO 0 messages
  return CAN1->RF0R & 0x3UL;
}


uint8_t counter = 0;
uint8_t counter1 = 0;
uint8_t frameLength = 0;
uint8_t frameLength1 = 0;
unsigned long previousMillis = 0;     // stores last time output was updated
unsigned long previousMillis1 = 0;
const long interval = 200;           // transmission interval (milliseconds)
const long interval1 = 200;

void setup() {
  Serial3.begin(115200);
  //bool ret = CANInit(CAN_500KBPS, 0);  // CAN_RX mapped to PA11, CAN_TX mapped to PA12
  bool ret = CANInit(CAN_125KBPS, 2);  // CAN_RX mapped to PB8, CAN_TX mapped to PB9
  //bool ret = CANInit(CAN_1000KBPS, 0);  // CAN_RX mapped to PA11, CAN_TX mapped to PA12
  //bool ret = CANInit(CAN_1000KBPS, 2);  // CAN_RX mapped to PB8, CAN_TX mapped to PB9
  //bool ret = CANInit(CAN_1000KBPS, 3);  // CAN_RX mapped to PD0, CAN_TX mapped to PD1
  if (!ret) while(true);
}

void loop() {
  RadiopwrON();
  delay(200);
  RadioID();
  delay(200);
  CANReceiveSerial();
}

void RadiopwrON()
{
  CAN_msg_t CAN_TX_msg1;
 
  CAN_TX_msg1.data[0] = 0x63;
  CAN_TX_msg1.data[1] = 0x00;
  CAN_TX_msg1.data[2] = 0x00;
  CAN_TX_msg1.data[3] = 0x00;
  CAN_TX_msg1.data[4] = 0x00;
  CAN_TX_msg1.data[5] = 0x00;
  CAN_TX_msg1.len = 6;
  //CAN_TX_msg1.len = frameLength1;

 

  unsigned long currentMillis1 = millis();
  if (currentMillis1 - previousMillis1 >= interval1) {
    previousMillis1 = currentMillis1;
    //if ( ( counter1 % 2) == 0) {
      //CAN_TX_msg1.type = DATA_FRAME;
      //if (CAN_TX_msg1.len == 0) CAN_TX_msg1.type = REMOTE_FRAME;
      //CAN_TX_msg1.format = STANDARD_FORMAT;
      CAN_TX_msg1.id = 0x000;
    //}
    CANSend(&CAN_TX_msg1);
    //frameLength1++;
    //if (frameLength1 == 7) frameLength1 = 0;
    //counter1++;
  }
}

void RadioID()
{
  CAN_msg_t CAN_TX_msg;

  CAN_TX_msg.data[0] = 0xFD;
  CAN_TX_msg.data[1] = 0x16;
  CAN_TX_msg.data[2] = 0x3F;
  CAN_TX_msg.data[3] = 0xFF;
  CAN_TX_msg.data[4] = 0xFF;
  CAN_TX_msg.data[5] = 0xFF;
  CAN_TX_msg.data[6] = 0xFF;
  CAN_TX_msg.data[7] = 0xFF;
  CAN_TX_msg.len = 8;
  //CAN_TX_msg.len = frameLength;

 

  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    //if ( ( counter % 2) == 0) {
      //CAN_TX_msg.type = DATA_FRAME;
      //if (CAN_TX_msg.len == 0) CAN_TX_msg.type = REMOTE_FRAME;
      //CAN_TX_msg.format = STANDARD_FORMAT;
      CAN_TX_msg.id = 0x415;
    //}
    CANSend(&CAN_TX_msg);
    //frameLength++;
    //if (frameLength == 9) frameLength = 0;
   //counter++;
  }
}

void CANReceiveSerial()
{
  CAN_msg_t CAN_RX_msg;
  if(CANMsgAvail()) {
    CANReceive(&CAN_RX_msg);

    if (CAN_RX_msg.format == EXTENDED_FORMAT) {
      Serial3.print("Extended ID: 0x");
      if (CAN_RX_msg.id < 0x10000000) Serial3.print("0");
      if (CAN_RX_msg.id < 0x1000000) Serial3.print("00");
      if (CAN_RX_msg.id < 0x100000) Serial3.print("000");
      if (CAN_RX_msg.id < 0x10000) Serial3.print("0000");
      Serial3.print(CAN_RX_msg.id, HEX);
    } else {
      Serial3.print("Standard ID: 0x");
      if (CAN_RX_msg.id < 0x100) Serial3.print("0");
      if (CAN_RX_msg.id < 0x10) Serial3.print("00");
      Serial3.print(CAN_RX_msg.id, HEX);
      Serial3.print("     ");
    }

    Serial3.print(" DLC: ");
    Serial3.print(CAN_RX_msg.len);
    if (CAN_RX_msg.type == DATA_FRAME) {
      Serial3.print(" Data: ");
      for(int i=0; i<CAN_RX_msg.len; i++) {
        Serial3.print("0x");
        Serial3.print(CAN_RX_msg.data[i], HEX);
        if (i != (CAN_RX_msg.len-1))  Serial3.print(" ");
      }
      Serial3.println();
    } else {
      Serial3.println(" Data: REMOTE REQUEST FRAME");
    }
  }
}
 

Offline poot36Topic starter

  • Frequent Contributor
  • **
  • Posts: 678
  • Country: ca
Well I found by pressing on the main FPGA chip in the unit that I was able to influence if the illumination came on or not.  So I tried to reflow it with one of those Chinese hot air stations but I think I may have done more damage then good as the current draw is now around 1.4A and no lights.  I was not able to get the chip hot enough to even move a little even at 430C and 6 air flow.
 

Offline james_s

  • Super Contributor
  • ***
  • Posts: 21611
  • Country: us
If you roasted the IC at 430C you probably destroyed it. You really should not be trying to reflow BGAs unless you know what you're doing, and certainly you should practice on some scrap rather than on the device you're trying to repair.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf