PWM LED rojo en Stellaris Launchpad

0

Estoy intentando encender el LED rojo en un Stellaris LaunchPad, siguiendo la receta en la hoja de datos p.706 , tomando un par de accesos directos de la Stellaris® Peripheral Driver Library . No puedo entender por qué el LED no brilla. Espero un ciclo de trabajo del 50% a 5 kHz PWM. ¿Alguien ve lo que estoy pasando por alto aquí?

EDITAR: En la media mientras estrechaba el problema. Si incluyo una línea extra:

ROM_TimerConfigure(TIMER0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_B_PWM);

en la viñeta 2 el programa comienza a funcionar. Esto es lo que quiero decir en mis comentarios de que las llamadas a la ROM no están muy bien documentadas ya que es difícil identificar qué registros se escriben realmente.

#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/cpu.c"
#include "driverlib/gpio.h"
#include "driverlib/rom.h"
#include "inc/hw_sysctl.h"
#include "driverlib/sysctl.h"
#include "driverlib/timer.c"

#include <stdint.h>

#define LED_RED GPIO_PIN_1

int main() {
    // Set system clock to 80 MHz using PLL and external 16 MHz crystal.
    ROM_SysCtlClockSet(SYSCTL_SYSDIV_2_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);

    // Enable GPIO for LED.
    ROM_SysCtlPeripheralEnable( SYSCTL_PERIPH_GPIOF );
    ROM_GPIOPinWrite( GPIO_PORTF_BASE , LED_RED , 0x00 );
    ROM_GPIOPinTypeGPIOOutput( GPIO_PORTF_BASE , LED_RED );

    // Enable timer peripheral.
    ROM_SysCtlPeripheralEnable( SYSCTL_PERIPH_TIMER0 );
    // the GP Timer module clock must be enabled before the registers can be programmed (see page 313 or page 330).
    HWREG( SYSCTL_RCGCTIMER ) |= SYSCTL_RCGCTIMER_R0;
    // There must be a delay of 3 system clocks after the Timer module clock is enabled before any Timer module registers are accessed.
    ROM_SysCtlDelay( 1 );

    // Configure output pin for PWM use.
    ROM_GPIOPinConfigure( GPIO_PF1_T0CCP1 );
    ROM_GPIOPinTypeTimer( GPIO_PORTF_BASE , LED_RED );  //ROM_GPIOPinTypePWM( GPIO_PORTF_BASE , LED_RED ); => No PWM units on board, the timers are used for PWM.

    // LED_RED on PF1 is convenient.
    // PF1: T0CCP1 => 16/32-Bit Timer 0 Capture/Compare/PWM 1. (muxed with: PB7)
    // PWM 1 implies use of Timer B

    // PWM Mode
    // A timer is configured to PWM mode using the following sequence:
    // 1. Ensure the timer is disabled (the TnEN bit is cleared) before making any changes.
    ROM_TimerDisable( TIMER0_BASE , TIMER_B );

    // 2. Write the GPTM Configuration (GPTMCFG) register with a value of 0x0000.0004.
    HWREG( TIMER0_BASE + 0x000 ) = 0x00000004;

    // 3.In the GPTM Timer Mode (GPTMTnMR) register, set the TnAMS bit to 0x1, the TnCMR bit to 0x0, and the TnMR field to 0x2.
    HWREG( TIMER0_BASE + 0x004 ) |= TIMER_TBMR_TBAMS | TIMER_TBMR_TBMR_PERIOD;

    // 4. Configure the output state of the PWM signal (whether or not it is inverted) in the TnPWML field of the GPTM Control (GPTMCTL) register.
    HWREG( TIMER0_BASE + 0x00c ) |= 0;  // TIMER_CTL_TAPWML

    // 5. If a prescaler is to be used, write the prescale value to the GPTM Timer n Prescale Register (GPTMTnPR).
    //HWREG( TIMER0_BASE + 0x038 ) = ...

    // 6. If PWM interrupts are used, configure the interrupt condition in the TnEVENT field in the
    // GPTMCTL register and enable the interrupts by setting the TnPWMIE bit in the GPTMTnMR
    // register. Note that edge detect interrupt behavior is reversed when the PWM output is inverted
    //HWREG( TIMER0_BASE + 0x00c ) |= ...

    // 7. Load the timer start value into the GPTM Timer n Interval Load (GPTMTnILR) register.
    HWREG( TIMER0_BASE + 0x02c ) = 16000 - 1;   // 16000 @ 80MHz system clock makes 5 kHz PWM

    // 8. Load the GPTM Timer n Match (GPTMTnMATCHR) register with the match value.
    HWREG( TIMER0_BASE + 0x034 ) = 8000 - 1;    // Defines duty cycle

    // 9. Set the TnEN bit in the GPTM Control (GPTMCTL) register to enable the timer and begin generation of the output PWM signal.
    HWREG( TIMER0_BASE + 0x00c ) |= TIMER_CTL_TBEN; 

    // In PWM Timing mode, the timer continues running after the PWM signal has been generated. The
    // PWM period can be adjusted at any time by writing the GPTMTnILR register, and the change takes
    // effect at the next cycle after the write.

    while ( 1 ) {
    }
}
    
pregunta jippie

1 respuesta

1

Estaba escribiendo en GPTMTAMR donde debería escribir en GPTMTBMR (viñeta # 3 en los comentarios). En otras palabras, estaba escribiendo un valor en un registro timerA donde debería estar usando timerB. Se agregó el código final como una simple prueba de concepto para PWM, el LED rojo en Stellaris LaunchPad.

#include "inc/hw_types.h"
#include "driverlib/gpio.h"
#include "driverlib/rom.h"
#include "inc/hw_sysctl.h"
#include "driverlib/sysctl.h"
#include "driverlib/timer.c"

#include <stdint.h>

#define LED_RED GPIO_PIN_1

uint16_t period = 5000;
uint16_t dutyCycle = 0;

int main() {
    // Set system clock to 80 MHz using PLL and external 16 MHz crystal.
    ROM_SysCtlClockSet(SYSCTL_SYSDIV_2_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);

    // Enable GPIO for LED.
    ROM_SysCtlPeripheralEnable( SYSCTL_PERIPH_GPIOF );

    // Enable timer peripheral.
    ROM_SysCtlPeripheralEnable( SYSCTL_PERIPH_TIMER0 );

    // the GP Timer module clock must be enabled before the registers can be programmed (see page 313 or page 330).
    HWREG( SYSCTL_RCGCTIMER ) |= SYSCTL_RCGCTIMER_R0;
    // There must be a delay of 3 system clocks after the Timer module clock is enabled before any Timer module registers are accessed.
    ROM_SysCtlDelay( 1 );

    // Configure output pin for PWM use.
    ROM_GPIOPinConfigure( GPIO_PF1_T0CCP1 );
    ROM_GPIOPinTypeTimer( GPIO_PORTF_BASE , LED_RED );  //ROM_GPIOPinTypePWM( GPIO_PORTF_BASE , LED_RED ); => No PWM units on board, the timers are used for PWM.

    // LED_RED on PF1 is convenient.
    // PF1: T0CCP1 => 16/32-Bit Timer 0 Capture/Compare/PWM 1. (muxed with: PB7)
    // PWM 1 implies use of Timer B

    // PWM Mode
    // A timer is configured to PWM mode using the following sequence:
    // 1. Ensure the timer is disabled (the TnEN bit is cleared) before making any changes.
    ROM_TimerDisable( TIMER0_BASE , TIMER_B );

    // 2. Write the GPTM Configuration (GPTMCFG) register with a value of 0x0000.0004.
    // ROM_TimerConfigure(TIMER0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_B_PWM);
    HWREG( TIMER0_BASE + 0x000 ) = 0x00000004;

    // 3.In the GPTM Timer Mode (GPTMTnMR) register, set the TnAMS bit to 0x1, the TnCMR bit to 0x0, and the TnMR field to 0x2.
    HWREG( TIMER0_BASE + 0x008 ) |= TIMER_TBMR_TBAMS | TIMER_TBMR_TBMR_PERIOD;

    // 4. Configure the output state of the PWM signal (whether or not it is inverted) in the TnPWML field of the GPTM Control (GPTMCTL) register.
    HWREG( TIMER0_BASE + 0x00c ) |= 0;  // TIMER_CTL_TAPWML

    // 5. If a prescaler is to be used, write the prescale value to the GPTM Timer n Prescale Register (GPTMTnPR).
    //HWREG( TIMER0_BASE + 0x038 ) = ...

    // 6. If PWM interrupts are used, configure the interrupt condition in the TnEVENT field in the
    // GPTMCTL register and enable the interrupts by setting the TnPWMIE bit in the GPTMTnMR
    // register. Note that edge detect interrupt behavior is reversed when the PWM output is inverted
    //HWREG( TIMER0_BASE + 0x00c ) |= ...

    // 7. Load the timer start value into the GPTM Timer n Interval Load (GPTMTnILR) register.
    // ROM_TimerLoadSet(  TIMER0_BASE, TIMER_B, period - 1 );
    HWREG( TIMER0_BASE + 0x02c ) = period - 1;  // 16000 @ 80MHz system clock makes 5 kHz PWM

    // 8. Load the GPTM Timer n Match (GPTMTnMATCHR) register with the match value.
    // ROM_TimerMatchSet( TIMER0_BASE, TIMER_B, dutyCycle );
    HWREG( TIMER0_BASE + 0x034 ) = dutyCycle - 1;   // Defines duty cycle

    // 9. Set the TnEN bit in the GPTM Control (GPTMCTL) register to enable the timer and begin generation of the output PWM signal.
    // ROM_TimerEnable(   TIMER0_BASE, TIMER_B );
    HWREG( TIMER0_BASE + 0x00c ) |= TIMER_CTL_TBEN; 

    // In PWM Timing mode, the timer continues running after the PWM signal has been generated. The
    // PWM period can be adjusted at any time by writing the GPTMTnILR register, and the change takes
    // effect at the next cycle after the write.


    while ( 1 ) {
        //ROM_TimerMatchSet(TIMER0_BASE, TIMER_B, dutyCycle );
        HWREG( TIMER0_BASE + 0x034 ) = ( dutyCycle++ - 1 ); // Defines duty cycle
        if ( dutyCycle >= period - 1) {
            dutyCycle = 0;
        }
        ROM_SysCtlDelay(9000 / 3 );
    }
}
    
respondido por el jippie

Lea otras preguntas en las etiquetas