Sunday, 7 April 2013

STM32 System and Timer Clock Configurations - Pt2

Now that I've verified my system's core clock is functioning as expected, I can move onto configuring the clock modules to produce the desired BLANK and GSCLK signals to control the TLC5940 chips.

Using the SYSCLK signal, the 'Advanced High-performance Bus' (AHB) clock frequency is set via a prescaler. In this case I am using the maximum frequency of the AHB by setting the prescaler to divide by 1. The two 'Advanced Peripheral Bus' clocks (APB1 and APB2) are generated from the AHB via their associated prescalers. They have maximum frequencies of 42 and 84MHz respectively, so my APB1 prescaler is set to '4' and APB2 prescaler is set to '2'. The internal signal that can be selected as the timer peripherals' clock is the APB1 clock.

HOWEVER... and this is an important part to take note of: While the APB1 signal provides the clock for numerous peripherals including the timer modules, the timers can receive a faster clock if the APB1 prescaler is set to anything other than '1'. The manual states:
  1. If the APB prescaler is 1, the timer clock frequencies are set to the same frequency as that of the APB domain to which the timers are connected.
  2. Otherwise, they are set to twice (×2) the frequency of the APB domain to which the timers are connected.
Since the APB1 prescaler I am using is '4' and the AHB clock is 168MHz, the internal clock presented to the timer modules is actually (168/4) * 2 = 84MHz. Inside the TIMx modules there are three main clock signals:
  • CK_INT - The internal clock before prescaling
  • CK_PSC - The clock signal after being divided by the prescaler
  • CK_CNT - The counter clock, which generates pulses every time the prescaler counter overflows
Note that while there are different clock signals (internal clock, external clock, internal triggers, etc) that can be used as the main input to each timer module, since I don't need to synchronise to external signals, I will use the default internal clock, APB1. The internal clock signal APB1 is fed into my main timer module TIM3. This module will be used to provide both the GSCLK signal on an external GPIO pin, and also to trigger/clock the slave TIM4 module which will provide the BLANK pulses. Initially I intend to have the TIM3 setup for its fastest possible rate, and then configure the output for the desired GSCLK frequency once both signals are synchronised correctly. I am using a prescaler divide factor of 1 (TIM3_PSC = 0), so CK_PSC = CK_INT = APB1 * 2 = 84MHz.

Each TIM module from TIM2 to TIM5 (and some others) can be used as a 'master' or a 'slave' to generate signals or react to them in various ways. For instance, I can use TIM3 as a master that generates a trigger pulse every time the counter reaches a specific value. I could then use that trigger pulse as the main clock signal in another timer module.

The way I intend to use TIM3 is to use its 'Update Event' as its external trigger signal (TRGO) which generates a single pulse every time its counter 'overflows', or reaches the upper limit which is set in the 'Auto Reload Register' (ARR). The TIM3 counter is configured in 'Upcounter Mode' which means that every rising edge of the counter clock causes the counter to increment until it reaches the ARR value. When it reaches this upper limit, it generates an 'Update Event', UEV, which causes the counter to reset to '0'. Each UEV pulses the trigger signal, so if ARR is set to '1', the counter moves from 0 to 1, generates a trigger pulse, resets the counter to 0, and the process repeats forever.

This two-count overflow acts as a divide-by-two on the CK_CNT signal. Therefore, our TIM3 master trigger signal is 84MHz / 2 = 42MHz.

This trigger is passed into TIM4 on the Internal Trigger network, which, when these two specific timers are used, is the Internal Trigger 2 signal (ITR2).

Returning to the original task of providing grayscale clock and blanking pulse signals for the TLC5940, the two timer modules now need to be configured to generate these signals on their Output Compare pins.

For the GSCLK signal, the TIM3 Output Compare Channel 1 (OC1) signal is configured to toggle its output every time the counter matches the desired value; in this case '1'. This essentially means that it is synchronised with the TRG0 signal at half the frequency.

For the BLANK signal, we need to be able to synchronise the signals with a phase shift so that the desired number of GSCLK pulses are generated before a blanking pulse is generated. To do this, the TIM4 counter is configured in 'Centre Aligned' mode, so that it counts up to the ARR value and then counts down to zero and repeats. The TIM4 OC1 signal is configured as a PWM signal that is set when the counter is less than OC1's  Capture/Compare Register (CCR1) value, where:
  • CCR1 = GSCLK_COUNT + 1
Due to internal timing, the TIM3 OC1 signal is given a slight phase shift relative to the TIM4 OC1, and the result is that the number of rising edges between consecutive blanking pulses is the desired number (GSCLK_COUNT). I'm still not exactly sure why, so I'll need to investigate the origin of this phase shift, but for now I am happy that it's there.

The timing for each timer module, and the resulting signals seen by the TLC5940 chip are shown below in Fig.1. Here GSCLK_COUNT is set to '2'. Note that for TIM4, the CK_INT is TIM3's TRG0.

Figure 1: TIM3, TIM4, and the TLC5940 Signal Configuration

I've experimented with changing the TIM3 prescaler to adjust the GSCLK frequency, different numbers of GSCLK_PULSES. Below Fig. 2 and Fig. 3 show scope captures of two different configurations:

Figure 2: GSCLK = 21MHz, GSCLK_COUNT = 2
Figure 3: GSCLK = 82kHz, GSCLK_COUNT = 4

Now that the timing of the TLC5940 GSCLK and BLANK signals have been configured and are easily adjustable for the desired frequency and intensity resolution, it's time to move onto the TLC5940's serial data interface.

6 comments:

  1. Wow that is going to be an awesome project with that many leds. I am trying to drive a Tlc5940 with stm32 too, is there any chance you can provide the source of the library? Thnx!

    grtz Sander

    ReplyDelete
  2. Hey Sander, the code's a little experimental right now (read: messy as hell), but I'll clean it up (especially the DMA accesses) and post some helpful bits!

    ReplyDelete
  3. Great Work!
    I'm trying to work with STM32f4 + TLC5940, too.
    With bitbanging everything works but when I use the Hardware SPI something went wrong and I stil can't figure out what :(

    can you provide me some exampel code with the hardware SPI + DMA please?

    ReplyDelete
  4. Hey Roland, sorry for the delayed response. I've got a few boards up and running now, so I have a bit of time to clean up the code and blog about it.
    Expect an update tonight. :)

    ReplyDelete
  5. Hey guys, I've just update the blog with some SPI/DMA code: http://dohzer.blogspot.com.au/2013/06/stm32f4-spi-with-dma.html
    Hopefully you've already solved your problems, but let me know if anything is unclear (there's a lot of information there).

    ReplyDelete
  6. THANK YOU!! I spent like a week's worth of evenings trying to figure out why my TIMER timeout was twice as fast as expected. I did not see that tiny, unobvious little section in the manual. Thanks again.

    ReplyDelete