(Details of RCC configuration can be found in Section 5, "Reset and clock control (RCC)" in "RM0090 - Reference Manual - STM32F405xx, STM32F407xx, STM32F415xx and STM32F417xx advanced ARM-based 32-bit MCUs", available for download from ST Microelectronics.)
To arrive at a SPI bit rate of 6.4063 MHz:
1) Set M, N, and P to yield a main PLL frequency of 102.5 MHz.
VCO(in) = HSE / M, and must be 1 ≤ VCO(in) ≤ 2 MHz; set M = 4 to yield (HSE is an 8 MHz crystal):
VCO(in) = 8 MHz / 4 = 2 MHz
VCO(out) = VCO(in) × N, and must be 64 ≤ VCO(out) ≤ 432 MHz; set N = 205 to yield:
VCO(out) = 2 MHz × 205 = 410 MHz
PLL(general) = VCO(out) / P, and must be PLL(general) ≤ 168 MHz; set P = 4 to yield:
PLL(general) = 410 MHz / 4 = 102.5 MHz
Note that PLL(general) is SYSCLK.
(The value of Q, which divides VCO(out) for the USB OTG FS, SDIO, and RNG clocks, doesn't matter. I set mine to 9 to yield a rate of 45.6 MHz so that I could use the RNG if I chose, in which case the RNG clock must be ≤ 48 MHz.)
2) Set the HCLK (for AHB) divisor to 1 to yield an AHB clock of 102.5 MHz.
3) Set the PCLK1 (for APB1) and PCLK2 (for APB2) divisors to 4 and 2, respectively.
Constraints: max PCLK1 = 42 MHz; max PCLK2 = 84 MHz.
PCLK1 = HCLK / 4 = 102.5 MHz / 4 = 25.625 MHz (low speed APB1 bus clock)
PCLK2 = HCLK / 2 = 102.5 MHz / 2 = 51.25 MHz (high speed APB2 bus clock)
4) Set the SPI peripheral baud rate prescaler to 8 (for SPI1, on the high speed APB2 bus) or 4 (for SPI2 or SPI3, both on the low speed APB1 bus).
SPI baud rate = PCLKn / prescaler
For SPI1:
SPI baud rate = PCLK2 / 8 = 51.25 MHz / 8 = 6.4063 MHz
For SPI2 and SPI3:
SPI baud rate = PCLK1 / 4 = 25.625 MHz / 4 = 6.4063 MHz
Saturday, January 19, 2013
Fun with RGB LED Strips - Part 3: WS2811 Timing
The WS2811 is a nice little constant-current three-output PWM LED driver with a single data input and one data output for chaining. After a reset condition (more on that in a moment), each device will look for and interpret 24 bits of data, 8 bits per color component (sent MSB first), with each bit being sent as a hi/lo NRZ waveform with specific timing; once a device has read 24 bits, it then mirrors all subsequent data on its data out line. A reset waveform (low input for at least 50 µs) causes each device to update its RGB PWM outputs according to the RGB triplet it just read; the PWM state of these outputs stays as programmed until the device receives another RGB triplet and reset condition.
According to the WS2811 datasheet, the low-speed 400 KHz NRZ waveform timings are as follows (we'll ignore rise and fall times and permissible slop for now and just focus on idealized timings):
The datasheet does not give explicit timings for the high-speed 800 KHz data rate, but rather just indicates that all parameters are half of the given 400 KHz values except for the reset condition minimum duration of 50 µs (though it's not clear whether the "half" also applies to the parameter tolerance of ± 150 ns). Therefore the high-speed 800 KHz timings will be:
I didn't want to bit-bang since that's not very portable. The best approach seemed to be to try to make use of a serial peripheral. Speeds on the USARTs aren't as high as would be required, so I decided to look at SPI instead. The most logical approach would be to treat each NRZ pattern as an 8-bit byte and then attempt to come up with a SPI peripheral clock that would provide edges as close to the nominal timings as possible. The NRZ pattern period at 800 KHz is 1.25 µs; 1/8 of that period is 156.25 ns which is a bit rate of 6.4 MHz. That would be my target.
The processor on my Discovery board is an ST Microelectronics STM32F407 and has an 8 MHz external crystal. The STM32F4xx family contains a reasonably sophisticated clock generation scheme (the RCC subsystem); after a little calculation, I determined that I could configure the clocks to provide a 25.625 MHz SPI peripheral clock, and divide by 4 to yield a SPI bit clock of 6.4063 MHz, or a bit timing of 156.10 ns.
Here's a comparison of the edges at this bit rate with the desired 800 KHz NRZ pattern edges:
Two of the SPI bit edges align with the ideal NRZ edges with errors of 62 and 24 ns. This should let me generate NRZ hi and lo times that are within the tolerances given in the WS2811 datasheet, even if those tolerances are divided by 2 for 800 KHz operation (± 75 ns).
According to the choices of edges above, to generate a '0' pattern, I'll have to send two high bits followed by six low bits (byte value = 0xC0); to generate a '1' pattern, I'll send four high bits followed by four low bits (byte value = 0xF0).
This means that for every 24-bit RGB triplet, I'll send 24 separate bytes - one for each bit in the triplet. Note that since the patterns both contain multiples of 2 bits' worth of ones and zeros, I could optimize memory usage by halving the SPI bit rate and sending two NRZ bit patterns at a time (one in each nybble of the transmitted SPI byte); to get things going, however, I decided to defer making this optimization until later.
Before continuing with implementation, I'll make a separate post describing the STM32Fxx clock configuration for anyone who might be interested.
According to the WS2811 datasheet, the low-speed 400 KHz NRZ waveform timings are as follows (we'll ignore rise and fall times and permissible slop for now and just focus on idealized timings):
I didn't want to bit-bang since that's not very portable. The best approach seemed to be to try to make use of a serial peripheral. Speeds on the USARTs aren't as high as would be required, so I decided to look at SPI instead. The most logical approach would be to treat each NRZ pattern as an 8-bit byte and then attempt to come up with a SPI peripheral clock that would provide edges as close to the nominal timings as possible. The NRZ pattern period at 800 KHz is 1.25 µs; 1/8 of that period is 156.25 ns which is a bit rate of 6.4 MHz. That would be my target.
Here's a comparison of the edges at this bit rate with the desired 800 KHz NRZ pattern edges:
Two of the SPI bit edges align with the ideal NRZ edges with errors of 62 and 24 ns. This should let me generate NRZ hi and lo times that are within the tolerances given in the WS2811 datasheet, even if those tolerances are divided by 2 for 800 KHz operation (± 75 ns).
According to the choices of edges above, to generate a '0' pattern, I'll have to send two high bits followed by six low bits (byte value = 0xC0); to generate a '1' pattern, I'll send four high bits followed by four low bits (byte value = 0xF0).
This means that for every 24-bit RGB triplet, I'll send 24 separate bytes - one for each bit in the triplet. Note that since the patterns both contain multiples of 2 bits' worth of ones and zeros, I could optimize memory usage by halving the SPI bit rate and sending two NRZ bit patterns at a time (one in each nybble of the transmitted SPI byte); to get things going, however, I decided to defer making this optimization until later.
Before continuing with implementation, I'll make a separate post describing the STM32Fxx clock configuration for anyone who might be interested.
Friday, January 18, 2013
Fun with RGB LED Strips - Part 2
This evening I finally managed to successfully drive my LED strip at 800 KHz. Here's the obligatory moving rainbow disco video:
The WS2811 is, let's say... particular... about its NRZ edges at 800 KHz. My first shot at selecting a SYSCLK frequency and dividing down from it worked brilliantly for 400 KHz (literally - these SMD5050s are quite bright), but resulted in mostly white light when I cut the divisor for 800 KHz. I'll describe clock configuration in a later post.
In the video above, I'm initiating the SPI DMA at 60 Hz by waiting on a timer. For kicks, I also tried waiting on DMA completion. It looks like this (the effective update rate is somewhere a little above 500 Hz):
Here's a 'scope screenshot showing the timing of the associated data bursts (at the above 'fast' rate):
Here are two screenshots showing individual NRZ bits; first the '0' pattern, then the '1' pattern:
Next up: driving the WS2811 and clock configuration... With luck, tomorrow. :-)
The WS2811 is, let's say... particular... about its NRZ edges at 800 KHz. My first shot at selecting a SYSCLK frequency and dividing down from it worked brilliantly for 400 KHz (literally - these SMD5050s are quite bright), but resulted in mostly white light when I cut the divisor for 800 KHz. I'll describe clock configuration in a later post.
In the video above, I'm initiating the SPI DMA at 60 Hz by waiting on a timer. For kicks, I also tried waiting on DMA completion. It looks like this (the effective update rate is somewhere a little above 500 Hz):
Here's a 'scope screenshot showing the timing of the associated data bursts (at the above 'fast' rate):
Here are two screenshots showing individual NRZ bits; first the '0' pattern, then the '1' pattern:
Next up: driving the WS2811 and clock configuration... With luck, tomorrow. :-)
Sodium Acetate and Kitchen Science
A couple of weeks ago, I had an occasion to dig out my flask of sodium acetate I'd made a few years ago (I wanted to see if I could make it from scratch and get it to crystallize properly). If you're not familiar with it, sodium acetate is the chemical in "phase change" heating pads - the ones that have a clear liquid inside, and that solidify and release heat when you "click" a little metal disc in the corner of the pad; they are "recharged" by boiling the pad until the white solid inside becomes liquid again.
I'd made an Instructable about it - it's amusing to read. It was an interesting diversion, though I was a little concerned about having a neighbor see all of the glassware in my kitchen through the window and report me to the police, suspecting I was running a meth lab.
I'd made an Instructable about it - it's amusing to read. It was an interesting diversion, though I was a little concerned about having a neighbor see all of the glassware in my kitchen through the window and report me to the police, suspecting I was running a meth lab.
Tuesday, January 15, 2013
Fun with RGB LED Strips
I've had an interest in solid-state light sources - and all the fun things one could conceivably do with them - for some time now. Recently, I've actually had enough of a break in my absurdly insane work and home schedule to permit me to dip a pinky toe in the waters.
I've had my eye on the WS2811 from World Semi for a little while, and more recently the SMD5050 RGB SMD LED which incorporates a WS2811 in-package.
So I finally broke down and bought an RGB LED strip to give them a go (just a meter to start).
I had also recently acquired a Discovery Kit from ST Microelectronics and, since I work with the STM32 family quite a bit where I work, I decided I would use that as the driver platform (it features an STM32F407 microcontroller). I also wanted to write my own code for it - it's more fun that way. :-)
So far, I've had just enough time to get the basics of the driver working.
Yes, I know - the 'scope's a dinosaur. I haven't bothered to buy anything newer because I have access to excellent equipment at work. Besides which, when I do drag it into work with me (much of my equipment finds its way there at various points in time), I can be assured that it won't walk off. No one wants to use a 60 MHz 'scope. :-) Unfortunately, it's barely sufficient for this application, and while I'm getting the timings tweaked I'll probably have to bring things in to work with me for a bit.
Since driving a WS2811 isn't a straightforward process, I figured I would share my observations and perhaps my code as well, as I'm working on this project.
Now if I can only find another two or three hours of uninterrupted free time...
I've had my eye on the WS2811 from World Semi for a little while, and more recently the SMD5050 RGB SMD LED which incorporates a WS2811 in-package.
So I finally broke down and bought an RGB LED strip to give them a go (just a meter to start).
I had also recently acquired a Discovery Kit from ST Microelectronics and, since I work with the STM32 family quite a bit where I work, I decided I would use that as the driver platform (it features an STM32F407 microcontroller). I also wanted to write my own code for it - it's more fun that way. :-)
So far, I've had just enough time to get the basics of the driver working.
Yes, I know - the 'scope's a dinosaur. I haven't bothered to buy anything newer because I have access to excellent equipment at work. Besides which, when I do drag it into work with me (much of my equipment finds its way there at various points in time), I can be assured that it won't walk off. No one wants to use a 60 MHz 'scope. :-) Unfortunately, it's barely sufficient for this application, and while I'm getting the timings tweaked I'll probably have to bring things in to work with me for a bit.
Since driving a WS2811 isn't a straightforward process, I figured I would share my observations and perhaps my code as well, as I'm working on this project.
Now if I can only find another two or three hours of uninterrupted free time...
Subscribe to:
Posts (Atom)






