Other Parts Discussed in Thread: TM4C123GH6PM
I've been working on a new revision of a CCA we designed that has this micro onboard, supplanting a TM4C123GH6PM due to parts availability. One of the main differences in our application is that the new micro has only one CAN bus, CAN0, whereas there are 2 CAN buses on the legacy part. I'm currently using TivaWare v2.2.0.295 - this version supports a new API call to unlock special pins, which was needed in my application.
Regardless of how I attempt to instantiate and enable CAN0, I get nothing out of the Tx pin on the scope. I have a CAN message being transmitted every 250 ms. Interrupt handling was not working either, so I removed the transceiver so I could probe the pins from the micro directly. At first I suspected that I was making some sort of mistake in unlocking the special pin for one of the ports needed for CAN0 on Port F. However, after inspecting the SYSCTL registers for GPIO PORTF, I concluded that everything was indeed set correctly - I simply get a 3.3V constant output on the Tx pin.
CAN0 can also be setup on Port B and Port E, so I gave that a shot. Neither of the sets of pins on those ports are special pins, so the job is significantly more straightforward, but to no avail. I get the same response out of the Tx pins on the corresponding ports, a constant 3.3V output.
I have attempted to configure CAN0 using API calls as well as DRM calls, but achieve the same result. I looked up the errata for the micro and read the DID0 register for the device and silicon revision, but do not see anything indicating that my microprocessor has any issue with CAN0 or GPIO configuration (processor is a rev A1). I switched scopes to confirm the result and inspected the crystal oscillator configuration as well. I'm at a bit of a loss as standing up a CAN bus on a Cortex CPU has never been this challenging. Here's my initialization code for CAN0 on some of the alternative ports (port F and B):
Common initialization for my CCA:
ROM_SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_20MHZ);
ROM_SysCtlPWMClockSet(SYSCTL_PWMDIV_1);
gSysTickPeriod = ROM_SysCtlClockGet(); // no idea what speed this will result in yet...
// setup SysTick timer for 200 Hz interrupts
ROM_SysTickPeriodSet(gSysTickPeriod / MAIN_LOOP_FREQ);
// disable sleep mode on all peripherals being used
ROM_SysCtlPeripheralClockGating(true);
Port F Implementation
// Must unlock and configure PF0 since it defaults to GPIO and is a special config pin (NMI)
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_CAN0);
// use nominal API for non-special CAN pin
ROM_GPIOPinConfigure(GPIO_PF3_CAN0TX);
ROM_GPIOPinTypeCAN(GPIO_PORTF_BASE, GPIO_PIN_3);
// direct register programming required for special pin
HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY; // unlock pin
HWREG(GPIO_PORTF_BASE + GPIO_O_CR) = GPIO_PIN_0;
HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY; // unlock pin
HWREG(GPIO_PORTF_BASE + GPIO_O_AFSEL) |= GPIO_PIN_0;
#if 0
// using the ROM functions doesn't seem to be working for this
ROM_GPIOPinConfigure(GPIO_PF0_CAN0RX);
ROM_GPIOPinConfigure(GPIO_PF3_CAN0TX);
ROM_GPIOPinTypeCAN(GPIO_PORTF_BASE, GPIO_PIN_0 | GPIO_PIN_3);
#else
HWREG(GPIO_PORTF_BASE + GPIO_O_DEN) |= GPIO_PIN_0;
HWREG(GPIO_PORTF_BASE + GPIO_O_PCTL) |= 3U; // bit 3 of GPIOFPCTL is CAN0Rx
#endif
// lock the registers
HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY;
HWREG(GPIO_PORTF_BASE + GPIO_O_CR) = 0x00;
HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = 0;
Note that I had some issues using the API calls for configuring port F for CAN, so resorted to DRM instead.
Port B Configuration
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
ROM_GPIOPinConfigure(GPIO_PB4_CAN0RX);
ROM_GPIOPinConfigure(GPIO_PB5_CAN0TX);
ROM_GPIOPinTypeCAN(GPIO_PORTB_BASE, GPIO_PIN_4 | GPIO_PIN_5);
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_CAN0);
Subsequent CAN bus initialization
gCANbase = CAN0_BASE; // 0x40040000 // Reset the state of the message objects and the CAN module. CANInit(gCANbase); // Configure the controller for 1 Mbit operation. #if 1 uint32_t temp = CANBitRateSet(gCANbase, gSysTickPeriod, 1000000); #else tCANBitClkParms CANBitClk; CANBitClk.ui32SyncPropPhase1Seg = 5; CANBitClk.ui32Phase2Seg = 2; CANBitClk.ui32QuantumPrescaler = 5; CANBitClk.ui32SJW = 2; CANBitTimingSet(gCANbase, &CANBitClk); #endif // Enable interrupts for the CAN in the NVIC. IntEnable(gCANbase == CAN0_BASE ? INT_CAN0 : INT_CAN1); // Enable interrups from CAN controller. CANIntEnable(gCANbase, CAN_INT_MASTER | CAN_INT_STATUS); InitCANMessages(); // enable automatic retransmission behavior CANRetrySet(gCANbase, TRUE); // Take the CAN0 device out of INIT state. CANEnable(gCANbase);
Note that all of this code works fine on the legacy TM4C123GH6PM part on CAN1.
Thanks for looking.