This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C1290NCPDT: How can software detect which TM4C129 part (pinout) it is executing on?

Part Number: TM4C1290NCPDT
Other Parts Discussed in Thread: TM4C129EKCPDT,

I am working with a PCB that needs pin 62 of the TM4C129 MCU to be driven using PWM.  That is straightforward enough if the MCU part number is known at compile time.  But I would like to make it possible to use any of the TQFP-packaged TM4C129 variants without having to change the software.  About half of the parts (e.g. TM4C1290NCPDT) assign different functions to some pins (51-63) than other parts do (e.g. TM4C129EKCPDT).  Pin 62 is PK4/PWM6 on the former and PK5/PWM7 on the latter.  I would like to be able to detect at runtime which port/PWM needs to be configured to drive pin 62.  

I figured out how to do this by directly reading the MCU's Device Identification register and comparing with a list of PARTNO values from the datasheets, but I wondered if there was a better way.  Ideally, I would like to use something like SysCtlPeripheralPresent() that would indicate which pinout the current MCU uses, so I wouldn't have to maintain a list of PARTNO values (actually the maintenance isn't so bad, but actually testing that I got it right would require loading PCBs with each of the eight different MCU parts).

This is what I am doing now:

				#define DeviceIdentification1 (*( (volatile uint32_t*) ( 0x400FE000 + 0x004 ) ) )
				const uint32_t ReadOfDID1 = DeviceIdentification1;					// Read the MCU's DID1 register.
				const uint32_t ReadOfPARTNO = ( ReadOfDID1 >> 16 ) & 0x000000FF;	// Extract the PARTNO field.

				tracepointLogWithCommentAndValueMacro("Device Identification 1 register: 0x%08X", ReadOfDID1 );
				tracepointLogWithCommentAndValueMacro("PARTNO field: 0x%08X", ReadOfPARTNO );

				// Parts with PK4/PWM6 on pin 62.
				#define PARTNO_TM4C1290NCPDT (0x19)

				// Parts with PK5/PWM7 on pin 62.
				#define PARTNO_TM4C129EKCPDT (0x35)

				#warning "Expand this to test more CPU variants."
				if( ReadOfPARTNO == PARTNO_TM4C1290NCPDT )
				{

Thanks,

Steve

P.S.  FWIW, this wouldn't be an issue if the functions which are on MCU pins 59-62 on some parts weren't shifted over by one (to pins 60-63) on the other half of the parts, but of course it is too late to change that now.

  • HI Steve,

      You are doing the right thing to decode the device ID. I don't think using SysCtlPeripheralPresent() all by itself is the best way. A peripheral may appear on all package variants and you won't be able to tell which pinout you have just by reading if a peripheral is present. 

  • This is just a follow up with more complete code implementing the method discussed above.  It has been tested only on a TM4C129EKCPDT, but I think it should correctly set up PWM on pin 62 on any of the eight TM4C129 parts in TQFP packages.  The portion which detects the MCU part variant might be useful in other situations.

    // Detect the type of MCU at runtime and set up either PWM 6 or PWM 7, whichever one controls
    // pin 62 on the current MCU variant. 
    
    // PinMux could do some of this setup, but we need to make parts of it conditional on the MCU
    // variant, and other parts get auto-generated only if one of those is enabled.  So it is
    // easiest to just do it all here.
    
    // This set up is for the SYSCTL_PERIPH_PWM0 PWM "module", of which the MCU has only one.  It
    // contains four PWM "generator blocks".  Each PWM generator block has two PWM "output signals"
    // which correspond with the output number (0..7); they are not 0 and 1 for every block.
    // A single "control block" maps the pins and sets the pin polarities.
    MAP_SysCtlPeripheralEnable( SYSCTL_PERIPH_PWM0 );       // Enable the PWM module.
    SysCtlPWMClockSet( SYSCTL_PWMDIV_1 );                   // Set the clock divider for all PWM signals.
    
    // Set up PWM generator block 3, which conveniently controls both pin PWM6 and pin PWM7 making this
    // part the same regardless of the MCU variant.
    PWMGenConfigure( PWM0_BASE, PWM_GEN_3, PWM_GEN_MODE_DOWN | PWM_GEN_MODE_NO_SYNC );
    PWMGenPeriodSet( PWM0_BASE, PWM_GEN_3, 1831 );          // Sets to 60MHz/1831 = 32.7689787 KHz, almost 1Hz high.  That is an error of about 30 ppm.
    PWMGenEnable( PWM0_BASE, PWM_GEN_3 );                   // Start the timers in the PWM generator block.
    
    // Set up the PWM output signals (pins).  This part is dependent on the MCU variant.  I didn't
    // find a way to detect the variant using the TivaWare library (although SysCtlPeripheralPresent()
    // lets you test for the presence of various peripherals), but the Device Identification registers
    // in the MCU do provide that info.  I asked on the TI forum but didn't get any suggestions about
    // a better way to do this: https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1099046/tm4c1290ncpdt-how-can-software-detect-which-tm4c129-part-pinout-it-is-executing-on
    #define DeviceIdentification1 (*( (volatile uint32_t*) ( 0x400FE000 + 0x004 ) ) )
    const uint32_t ReadOfDID1 = DeviceIdentification1;                  // Read the MCU's DID1 register.
    const uint32_t ReadOfPARTNO = ( ReadOfDID1 >> 16 ) & 0x000000FF;    // Extract the PARTNO field.
    
    // Parts with PK4/PWM6 on pin 62.
    #define PARTNO_TM4C1290NCPDT (0x19)
    #define PARTNO_TM4C1292NCPDT (0x1C)
    #define PARTNO_TM4C129CNCPDT (0x24)
    #define PARTNO_TM4C129DNCPDT (0x27)
    
    // Parts with PK5/PWM7 on pin 62.
    #define PARTNO_TM4C1294NCPDT (0x1F)
    #define PARTNO_TM4C129ENCPDT (0x2D)
    #define PARTNO_TM4C1294KCPDT (0x34)
    #define PARTNO_TM4C129EKCPDT (0x35)
    
    bool PK4_PWM6_on_pin_62 = ( ReadOfPARTNO == PARTNO_TM4C1290NCPDT )
                           || ( ReadOfPARTNO == PARTNO_TM4C1292NCPDT )
                           || ( ReadOfPARTNO == PARTNO_TM4C129CNCPDT )
                           || ( ReadOfPARTNO == PARTNO_TM4C129DNCPDT );
    
    if( PK4_PWM6_on_pin_62 )
    {
        // Enable pin PK4 for PWM0 M0PWM6.  For these parts it should drive pin 62.
        MAP_GPIOPinConfigure( GPIO_PK4_M0PWM6 );
        MAP_GPIOPinTypePWM( GPIO_PORTK_BASE, GPIO_PIN_4 );
        PWMPulseWidthSet( PWM0_BASE, PWM_OUT_6, 1831/2 );       // Can adjust this to get 50% duty cycle.
        PWMOutputState( PWM0_BASE, PWM_OUT_6_BIT, true );
    }
    else
    {
        // Enable pin PK5 for PWM0 M0PWM7.  For these parts it should drive pin 62.
        MAP_GPIOPinConfigure( GPIO_PK5_M0PWM7 );
        MAP_GPIOPinTypePWM( GPIO_PORTK_BASE, GPIO_PIN_5 );
        PWMPulseWidthSet( PWM0_BASE, PWM_OUT_7, 1831/2 );       // Can adjust this to get 50% duty cycle.
        PWMOutputState( PWM0_BASE, PWM_OUT_7_BIT, true );
    }