Posts

Showing posts from May, 2021

Longan Nano : I2C Master

Image
 After SPI, serial and Gpio, the next building block is I2C/Master. That one is a bit peculiar. Overview/DMA It is actually a finite state machine.  Each transition of a I2C transmission is associated with  an event, with a corresponding "event" interrupt. The sequence is StartSent-AddressSent-DataDataData-BTC-Stop Simple enough. Where it becomes tricky is when you want to use DMA with it. You have to manage two interrupts source in parallel. It ends up as  :  1- Do the beginning as usual, using  plain I2C interrupt events. 2- When reaching the "data" stage, start a DMA transfer + disable I2C event interrupt (we trigger the DMA transfer only if the # of data is > 2, else we do it using basic interrupts) 3- When the DMA stage is done, re-enable the I2C event interrupts  to finish the transfer To give an example:  to refresh the SSD1306 screen in one step (1024 bytes), we only need ~ 6 interrupts ( 5 I2C + 1 DMA) rather than ~ 1030 interrupts in plain i2c interrupt

Longan NANO + WS2812B

Image
  Now that we have a working Tx only SPI+DMA, it's time to play with a new toy : WS2812B RGB leds. These are picky and encode 0 & 1 as high state/low state pulse of a given duration for a "0" and for another duration for a "1". So a zero is ~ 400 ns high, 800 ns low and a one is 800 ns high, 400 ns low, +-150ns. So we must find a spi speed giving us the right waveform AND which is simple enough to encode. The short version : The simpler is Clock divider=16, with 3 bits high/5 bits low and 5 bits high/3 bits low to give us the correct waveform So to encode a 0 bit, we send 3 bits at 1 and 5 bits at 0 => 0xE0 to encode a "1", we sent 5 bits at 1 and 3 bits at 0=> 0xf8 The conversion is a simple lookup table that converts 4 bits at a time and generate 32 bits output at a time. The drawback is that a single led needs 8*3=24 bytes in memory. Computation is easy, dma is cheap, and............. It works but the first led is acting funny. Let's h

Longan Nano, freeRTOS, drivers

Image
  Things are progressing nicely. I now have freeRTOS , Serial (with DMA), SPI (with DMA) and basic LCD support. The goal is to remove all dependencies toward the GD32 fw lib and the longduino externals ultimately. Why do that ? First, the low level GD32 library is just a wrapper on top of the registers. It does not do consistency check, it does not bring features/optimization/... The library i'm doing is a little bit higher level. You setup the DMA parameters and that''s it. In a single call. No need to do X calls to setup all registers one per one. Additionally, the coding style is a bit different. The GD32 firmware lib is using C macros so that SPI_CTL(SPI0) is the "Control" register of SPI0 I'm using a structure defining all the registers of a given SPI To get the same thing, i do spi0->CTL But it's basically the same thing, no ? Almost. The main difference is , under gdb, i can just do  p /x *spi0 to see all the registers of SPI0 and check everythin

simplerST7735, Longan nano, STM32duino, ...

Image
 The ST7735 LCD controller is very common and is actually close to a ILI9341 It is connected to either SPI or parralel bus  The problem is : How to make the code portable while having decent performances Option 1:  Use  #ifdef ATMEL, ESP32 It is fast, but the code becomes really ugly pretty fast. And each time you add a new target, you modifiy the existing code for everyone. Option 2: Use a very low level SPI abstraction. it is portable, but the performances are not so great Additionnaly, depending on the use case, since it is YOUR project, you can speed up things since you know what you are doing with the SPI. Option 3: (our) We have a small abstraction layer providing the following services : init() : Initialize the chip. Can be tuned to setup SPI,// bus,  LCD width/height/and chip specific initialization write/write16 : Send a single byte/uint16_t writeWords() : Send a buffer of 16 bits word floodWord() : Send the same word N times (The performances are very linked to the 2 last o