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.

Setup AIN0...AIN8 on ADC0 & M0PWM0 to M0PWM7 on PWM0 (TM4C123GH6PM)

Other Parts Discussed in Thread: EK-TM4C123GXL

Hi there,

I am facing a problem of configuring more than two adc channels. I am able to configure 1 ADC channel using ADC0. My problem is that I want to configure pins AIN0 to AIN8 as ADC such that I want to read 8 ADC inputs using ADC0. 

Similarly I want to configure M0PWM0 to M0PWM7 on PWM0  and I want to configure all PWMs with 100 % duty cycle. Kindly could you please provide me some code for both ADC & PWM.

BTW I am using EK-TM4C123GXL launchpad

I shall be very grateful to you.

Regards,

Mohsin

  • Hello Mohsin,

    Following is a code snippet for enabling 8 Channels for ADC0. You can load one of the existing examples in your IDE like hello_uart and then add the code below.

    uint32_t ADCData[8];

    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);

    GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3);
    GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3);
    ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_PROCESSOR, 0);
     
    ADCHardwareOversampleConfigure(ADC0_BASE, OverSample);
     
    ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH0);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 1, ADC_CTL_CH1);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 2, ADC_CTL_CH2);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 3, ADC_CTL_CH3);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 4, ADC_CTL_CH4);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 5, ADC_CTL_CH5);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 6, ADC_CTL_CH6);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 7, ADC_CTL_CH7 | ADC_CTL_IE | ADC_CTL_END);
     
    ADCIntRegister(ADC0_BASE, 0, ADC0IntHandler8ch);
     
    ADCIntClear(ADC0_BASE, 0);

    ADCSequenceEnable(ADC0_BASE, 0);

    ADCProcessorTrigger(ADC0_BASE, 0);

    // Wait for Conversion Interrupt

    while(!ADCIntStatus(ADC0_BASE, 0, false);

    ADCSequenceDataGet(ADC0_BASE, 0, &ADCData[0])

    Do print the ADC Data on the UART Terminal to make sure the data is as expected w.r.t to the Analog Input Voltage Pins.

    Once you complete this exercise we can then look at the PWM Example and build it from there

    Regards

    Amit Ashara

  • Hi Amit, Thanks for your reply. With your sample code, I have managed to configure 8 adc channels on ADC0. Now kindly could you please send me the sample code for configuring 8 PWM outputs on PWM0. Thanks again for your reply. Regards, Mohsin
  • Hello Mohsin,

    Have you made sure that the voltage given on the pads are correctly getting converted and read by the CPU. This is to avoid unnecessary debug later when the code evolves.

    If the above has been done, then there is an example for PWM in the TIVAWare examples/peripherals/pwm called invert.c. You can use the same code and then make sure that the PWM pins are configured. The GPIO Port and Pin corresponding to the PWM signals can be found in the Signal Description section of the PWM Chapter in the data sheet. Each PWM Pin pair (odd and even) correspond to one PWM_GEN. As an example PWM_OUT_0 and PWM_OUT_1 correspond to PWM_GEN_0. Just be sure to load the correct value in the Pulse Width API Call of the example/.

    I can help in correcting any code issue once you integrate the same using the example

    Regards

    Amit

  • Hi Amit,

    Yes voltage given on the pads are correctly getting converted and read by the CPU. I have already gone through  PWM  invert example. My query is how can I configure both PWM output with100% duty cycle and both should be identical not inverted.

    Regards,

    Mohsin

     

  • Hello Mohsin,

    Remove the while loop in the PWM code. That would prevent the inversion.

    For 100% DC remove the /4

        PWMPulseWidthSet(PWM0_BASE, PWM_OUT_0,
                         PWMGenPeriodGet(PWM0_BASE, PWM_OUT_0) / 4);

    Regards

    Amit

  • Dear Amit,

    Thanks for your help and support. I have few queries about the ADC and PWM configuration.

    ADC:

    Like you said, I configured 8 ADC channels and they all are working fine. My only query about adc is that can I use sequencer 3? I think I can't use sequencer 3 as FIF0 depth for SS3 is 1 and my requirement is 8. Kindly confirm my point. Secondly let say if I want to configure 10 ADC channels do I need to use more than one sequencer?

    PWM:

    Like you said, I am able to use the PWM invert.c sample example. The problem is that when I add this code in the application containing ADC as well, It doesn't seem to work correctly. Infact I am getting 1958 on ADC channel 7 as I should get 2481 for my 2V input. See my code below. I think PD0,PB6 and PD1, PB7 sharing the same pin on the launchpad. Kindly could you please help me in configuring the PWM as I want to configure 10 PWM. Kindly could you please provide me some code for configuring 10 PWM pins.  with 100% duty cycle.

    Regards,

    Mohsin

    void
    ConfigADC0(void)
    {
    //
    // The ADC0 peripheral must be enabled for use.
    //
    SysCtlADCSpeedSet(SYSCTL_ADCSPEED_1MSPS);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);


    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);

    // Set reference to the internal reference
    ADCReferenceSet(ADC0_BASE, ADC_REF_INT);

    GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3);
    GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3);


    ADCSequenceConfigure(ADC0_BASE, 3, ADC_TRIGGER_PROCESSOR, 0);


    ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH0);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 1, ADC_CTL_CH1);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 2, ADC_CTL_CH2);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 3, ADC_CTL_CH3);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 4, ADC_CTL_CH4);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 5, ADC_CTL_CH5);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 6, ADC_CTL_CH6);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 7, ADC_CTL_CH7 | ADC_CTL_IE | ADC_CTL_END);
    ADCIntRegister(ADC0_BASE, 0, ADC0IntHandler);
    //
    // Since sample sequence 0 is now configured, it must be enabled.
    //
    ADCSequenceEnable(ADC0_BASE, 0);

    //
    // Clear the interrupt status flag. This is done to make sure the
    // interrupt flag is cleared before we sample.
    //
    ADCIntClear(ADC0_BASE, 0);
    }

    void
    ConfigPWM0(void)
    {
    //
    // Set the PWM clock to the system clock.
    //
    SysCtlPWMClockSet(SYSCTL_PWMDIV_1);

    //
    // The PWM peripheral must be enabled for use.
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM0);

    //
    // For this example PWM0 is used with PortB Pins 6 and 7. The actual port
    // and pins used may be different on your part, consult the data sheet for
    // more information. GPIO port B needs to be enabled so these pins can be
    // used.
    // TODO: change this to whichever GPIO port you are using.
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);

    //
    // Configure the GPIO pin muxing to select PWM functions for these pins.
    // This step selects which alternate function is available for these pins.
    // This is necessary if your part supports GPIO pin function muxing.
    // Consult the data sheet to see which functions are allocated per pin.
    // TODO: change this to select the port/pin you are using.
    //
    GPIOPinConfigure(GPIO_PB6_M0PWM0);
    GPIOPinConfigure(GPIO_PB7_M0PWM1);

    //
    // Configure the GPIO pad for PWM function on pins PB6 and PB7. Consult
    // the data sheet to see which functions are allocated per pin.
    // TODO: change this to select the port/pin you are using.
    //
    GPIOPinTypePWM(GPIO_PORTB_BASE, GPIO_PIN_6);
    GPIOPinTypePWM(GPIO_PORTB_BASE, GPIO_PIN_7);

    //
    // Configure the PWM0 to count up/down without synchronization.
    // Note: Enabling the dead-band generator automatically couples the 2
    // outputs from the PWM block so we don't use the PWM synchronization.
    //
    PWMGenConfigure(PWM0_BASE, PWM_GEN_0, PWM_GEN_MODE_UP_DOWN |
    PWM_GEN_MODE_NO_SYNC);

    //
    // Set the PWM period to 250Hz. To calculate the appropriate parameter
    // use the following equation: N = (1 / f) * SysClk. Where N is the
    // function parameter, f is the desired frequency, and SysClk is the
    // system clock frequency.
    // In this case you get: (1 / 250Hz) * 16MHz = 64000 cycles. Note that
    // the maximum period you can set is 2^16 - 1.
    // TODO: modify this calculation to use the clock frequency that you are
    // using.
    //
    PWMGenPeriodSet(PWM0_BASE, PWM_GEN_0, 20000);

    //
    // Set PWM0 PD0 to a duty cycle of 25%. You set the duty cycle as a
    // function of the period. Since the period was set above, you can use the
    // PWMGenPeriodGet() function. For this example the PWM will be high for
    // 25% of the time or 16000 clock cycles (64000 / 4).
    //
    PWMPulseWidthSet(PWM0_BASE, PWM_OUT_0,
    PWMGenPeriodGet(PWM0_BASE, PWM_OUT_0) / 2);

    //
    // Enable the dead-band generation on the PWM0 output signal. PWM bit 0
    // (PD0), will have a duty cycle of 25% (set above) and PWM bit 1 will have
    // a duty cycle of 75%. These signals will have a 10us gap between the
    // rising and falling edges. This means that before PWM bit 1 goes high,
    // PWM bit 0 has been low for at LEAST 160 cycles (or 10us) and the same
    // before PWM bit 0 goes high. The dead-band generator lets you specify
    // the width of the "dead-band" delay, in PWM clock cycles, before the PWM
    // signal goes high and after the PWM signal falls. For this example we
    // will use 160 cycles (or 10us) on both the rising and falling edges of
    // PD0. Reference the datasheet for more information on dead-band
    // generation.
    //
    PWMPulseWidthSet(PWM0_BASE, PWM_OUT_1,
    PWMGenPeriodGet(PWM0_BASE, PWM_OUT_1) / 2);

    //
    // Enable the PWM0 Bit 0 (PD0) and Bit 1 (PD1) output signals.
    //
    PWMOutputState(PWM0_BASE, PWM_OUT_1_BIT | PWM_OUT_0_BIT, true);

    //
    // Enables the counter for a PWM generator block.
    //
    PWMGenEnable(PWM0_BASE, PWM_GEN_0);
    }

  • Hello Mohsin,

    The ADC on SS3 has only 1 entry so you cannot use it for the existing scenario. Also you are correct, for more than 8 you would need to use another Sample Sequencer

    Also on the PWM there are pins shared between ADC and PWM0. You would have to use PWM1 for such conflicting channels since ADC has fixed Pins.

    Regards

    Amit

  • Dear Amit,

    Thanks again for your help and support. I have now successfully able to configure both ADC and PWM for my application. Only problem which left is the UART bootloader. I want to add UART boot loader for my application. I have gone through the TIVA bootlaoder guide and have also gone through boot serial example as well.  My only query is that how I need to add UART Bootloader in my application. I am not much familiar with TI bootloader. If possible kindly could you please provide me some code containing UART bootloader such that firmware can be updated via UART.

    Thanks again for all your support.

    Regards,

    Mohsin

  • Hello Mohsin,

    The latest tivaware release there is a good example from TM4C129 device for a boot loader. You can try using the same as a reference.

    C:\ti\TivaWare_C_Series-2.1.0.12573\examples\boards\dk-tm4c129x\boot_demo_uart

    Also suggest you open a new thread on this as more community members would be able to help since now the context of the thread changes,

    Regards

    Amit

  • Hi Amit,

    I now want to configure 9 ADC channels so It means I need to use 2 sequencer. Kindly could you please provide me some code for this.

    Regards,

    Mohsin 

  • Hello Mohsin,

    You would need to use another sequencer, configure the IO for ADC Function and the Interrupt Handler for the sequencer. Hope it helps. Please note that the ADC conversion of the next sequencer will happen after Sequencer-0 is completed.

    ADCSequenceConfigure(ADC0_BASE, 1, ADC_TRIGGER_PROCESSOR, 1);
     

    ADCSequenceStepConfigure(ADC0_BASE, 1, 0, ADC_CTL_CH8 | ADC_CTL_IE | ADC_CTL_END);

     
    ADCIntRegister(ADC0_BASE, 1, ADC1IntHandler8ch);
     
    ADCIntClear(ADC0_BASE, 1);

    ADCSequenceEnable(ADC0_BASE, 1);

    ADCProcessorTrigger(ADC0_BASE, 1);

    Regards

    Amit