Category Archives: VoCore

Write Bin File by Bash & Awk

Sometimes I find I am locked out VoCore2 wifi, because some executable files missed or messed up the factory setting. The only exists connection is the uart console.

PS: if you messed up factory setting, the wireless driver will not work anymore, because the driver read factory setting for some important data such as mac address, timer offset etc…

I might have three choices:

1. connect a cable to ethernet port — but I do not have…
2. on, fix brick part, use another VoCore2 SPI reflash the flash — but I only have the broken one…
3. use iwpriv, manually set the driver — around 30+ settings, I am sure I do not want to do that…

so I am looking for a way using bash and awk to write a bin file, even it is slow, but no problem, I accept, at least it is fast than the upper ways.:)

We will need three commands, bash/awk/dd

Key to make this happen:
awk can do most of the work, but it can not write zero to a file, we will need use dd copy a zero from /dev/zero.



create_byte_map() {
dd if=/dev/zero of=/tmp/map bs=1 count=1 2> /dev/null
echo | awk '{ for(i = 0; i < 256; i++) { printf("%c", i); }}' >> /tmp/map

attach_byte() {
name=$1; byte=$2;
if [ -f $name ]; then size=`ls -l ${name} | awk '{print $5}'`; else size=0; fi
dd if=/tmp/map of=${name} bs=1 count=1 seek=${size} skip=${byte} 2> /dev/null

attach_bytes() {
name=$1; string=$2;
echo $string | awk -F " " '{for (i = 1; i <= NF; i++) print $i}' | while read byte
do attach_byte $name $byte; done


# example:
attach_bytes /tmp/myfile "`echo $1 | awk '{printf("184 216 18 103 0 88");}'`";
hexdump -C /tmp/myfile

If I want output some char(0~255) to a file, just call the bash function:
attach_bytes [output file] [char in decimal(0~255)]

This looks like stupid but sometimes it really helpful. If there is any clever way, let me know 🙂

VoCore2: Control RGB(WS2812B) LEDs

Now we can use VoCore2 control WS2812B based LED belt 🙂 Hope this helps you make a beautiful house.

This is a “big” project for me, it contains three parts.

  • Linux Driver
    I am using I2S interface, because the best timer on VoCore2 is 1us… WS2812 requests 800KHz, and its bit0, bit1 is special: 800ns high then 400ns low, it is its bit1, 400ns high then 800ns low it is its bit0. We can not use timer to output that.
    But There is a super good channel, it is I2S. I2S speed is up to 240MHz. I find a way to use three I2S bits to simulate one WS2812 bit, set I2S speed to 2400KHz. 🙂
    PS: I spend some time rewrite dma driver, so data is transfer from dma and VoCore2 is able to control 1024 LEDs at 30fps using less than 1% cpu.
  • API for user space
    I2S interface is not designed for such “common” usage, it is used to transfer audio data, so it is align with double word(4 byte), and have its special byte order, we can not send “abc” to I2S directly, because I2S real output will be “c?ab”. To use I2S interface, an API convert data order is necessary.
  • Hardware design.
    VoCore2 signal output voltage is 3.3V, WS2812B min signal voltage is 0.7 x Vcc = 3.5V, not match well. We’d better to use a buffer gate to convert the signal voltage for the accurate situation. This is option, without gate it still work, just sometime one or two LEDs are naughty. Connection is simple, I2S_SDO to WS2812B DATAIN.

“There is no secret in the source code.”

First is Linux Driver Code: ws2812b.c, put it into Linux kernel and add it to Makefile and Kconfig, also enable gdma at VOCORE2.dts, compile. If it works normal, it will create a system file at /sys/devices/10000000.palmbus/10002800.gdma/update

You can try “echo aaaa > /sys/devices/10000000.palmbus/10002800.gdma/update”, I2S_SDO will output wave like this:

PS: actually I2S received data is “aaaa\r”

Then API Source Code: ws2812_api

ws2812_reset(): call this to turn all LEDs off RGB(0,0,0).
ws2812_set(int *color, int size): set leds colors. example: you have 16 WS2812B in a line, you want to set them to different color, code should be like this (include ws2812.h)

		int color[] = {0x080000, 0x000800, 0x000008,
		               0x080000, 0x000800, 0x000008,
		               0x080000, 0x000800, 0x000008,
		               0x080000, 0x000800, 0x000008,
		               0x080000, 0x000800, 0x000008,
		ws2812_set(color, sizeof(color) / sizeof(int));

For more details, check unit test code at the end of ws2812.c.
The head photo is from this code 🙂 For me everything works well.

VoCore2: Wifi driver(mt7628.ko) for LEDE 2

Last time I have success make the driver work, but it is not done.

Currently the log is like this, call “ifconfig ra0 up”

[  113.627999] mt7628_switch_channel(): Switch to Ch#9(1T1R), BBP_BW=0
[  113.634363] SYNC - BBP R4 to 20MHz.l
[  113.935695] [PMF]ap_pmf_init:: apidx=0, MFPC=0, MFPR=0, SHA256=0
[  113.941908] MtAsicSetRalinkBurstMode(2821): Not support for HIF_MT yet!
[  113.948644] MtAsicSetPiggyBack(746): Not support for HIF_MT yet!
[  113.982402] mt7628_switch_channel(): Switch to Ch#4(1T1R), BBP_BW=1
[  113.988785] MtAsicSetTxPreamble(2800): Not support for HIF_MT yet!
[  113.995163] MtAsicSetPreTbtt(): bss_idx=0, PreTBTT timeout = 0xf0
[  114.001379] Main bssid = b8:d8:12:67:5f:b5
[  114.005593] <==== rt28xx_init, Status=0

But I stopped here, I can find the SSID in my computer wifi list, but I can not connect to it, the icon on computer(macbook) is keeping in “connecting” status. I think I must miss some key steps, normal log should be like this.

[  449.410000] <==== rt28xx_init, Status=0
[  449.540000] device ra0 entered promiscuous mode
[  449.540000] br-lan: port 2(ra0) entered forwarding state
[  449.550000] br-lan: port 2(ra0) entered forwarding state
[  451.550000] br-lan: port 2(ra0) entered forwarding state

After ifconfig up, there is no log about ra0 entered forwarding state :p I am a noob again, haha. If you reader happen to know my mystery issue, please leave a message to this post 🙂

Here is my compiled mt7628.ko for lede, do not depends on other kernel module, my command: "insmod mt7628.ko" and "ifconfig ra0 up" should make it work.

Also mediatek driver do not support openwrt uci interface, Linkit driver is using iwpriv to setup everything, another way is to use a config file in /etc/wireless/mt7628/mt7628.dat.

You can download here and copy to your lede.mt7628.dat

PS: the developing version lede is broken for VoCore2, lol, I guess somebody modify uart2 interrupt, now uart2 can not input any command to console, only able to output log to console, sad 🙂

VoCore2: Wifi driver(mt7628.ko) for LEDE

Finally I success make mediatek wifi driver run on LEDE 🙂 But mediatek do not allow to public the source code, I have to upload it somewhere as blob.

Now I guess a lot of features could unlock now.

1. monitor mode.
LEDE mt76 driver is very slow, but mediatek official driver is fast and stable.

2. more than one ssid.
we can create one ssid named VoCore2 and one named VoCore2-Guest for host and guest. It supports up to 16 ssid.

3. low level wifi control.
normally we use this for certification like FCC, KC…Last time I have to use mediatek openwrt, but now we can directly use LEDE.

VoCore2: Connect to SPI Screen 4

Now the LCD works 🙂

I change CPOL/CHPA from mode 0 to mode 3, that SPI wave shape is correct now.

Also finish a simple app to drive the TFT, refresh full screen from red/green/blue pixel by pixel. Download source code here: tft.c

From my test, the LCD screen max speed is around 3.8MHz (speed=49), can not reach 6MHz, that’s bad news. We can not use it as a game display but only for low frame rate usage — such as digital photo display, display 480×320 picture will take around 1~2 seconds.

Here is the real time video:

I called the following command in this video(tft is compiled from the source):

tft r 49
tft g 49
tft b 49

Power consume is 5V 0.21~0.23A, a little more than 1 watt, 10000mAh battery should make it last over 30 hours. 🙂

Next blog I will update the source code a little to make it display some real photos.

Crazy flash chip!

Recently six months flash chip price is almost doubled, it is a key chip of VoCore. The world is sick, nobody invest the chip factory and real economy…It is almost ten years since 2008, hope everything goes well.

Maybe its time to consider remove flash from VoCore and add a tf card slot 😂

I think it is possible, all we need in the flash chip is the bootloader, it is around 128KB, can be store in 1Mb flash, that one price is doubled but still acceptable 🙂

Bootloader will need add two drivers, one read from USB disk, one read from sd card. disk format is a problem, we can make bootloader use SD card first 16MB as the old flash, and read Linux from there.

Actually many customized u-boot has already done that. It’s time!

VoCore2: Connect to SPI Screen 3

Arrrr!!!! Last day after updated Eagle, I find it is now need to pay monthly…I know this six months delayed. 😅 Stupid autodesk. Thanks God, there is an opensource toolkit named KiCAD. I spend two days to study KiCAD, now EAGLE has moved into trash.

Now continue my adventure.

This time I will show you how to make spi master work.

I am trying to send some data to SPI, and data analyser read like this.

The screen protocol is like this: first bit is command/data bit, 0 means the following bits are command and 1 means the following data is parameter, from the upper picture, my send is data(1) + 0x78 + 0x56 + 0x34, totally it is 25 bits.

Send such SPI package is easy on VoCore2, you will need a directly memory writing tool, mine is mem, link here:

First. let’s setup its speed. (PS: do not forget download the datasheet) I want to set it to 2Mbps. From datasheet, it is 193.3MHz / (rs_clk_sel + 2) = 2Mbps, we get rs_clk_sel = 94.

Now read the register 0x10000b28, get its current value. We do not need change other bits of 0x10000b28, so we must read it and put same value back to it to make sure it works normal. call “mem 0x10000b28 bit”

root@OpenWrt:/# mem 0x10000b28 bit
31:1 30:1 29:1 28:0 27:0 26:0 25:0 24:0 23:0 22:0 21:0 20:1 19:0 18:0 17:1 16:0
15:1 14:0 13:0 12:0 11:1 10:0 09:0 08:0 07:1 06:0 05:0 04:0 03:0 02:1 01:0 00:0
= 0xE02E8884

rs_clk_sel is 27:16 bits, change the 8bits from 000000010010 to 000000101110 (94 in decimal), so we should set it to 0xe02e8884, call “mem 0x10000b28 0xe02e8884” write back the register.

Rest register is similar, set 0x10000b2c(for short, I will write 0x2c) command length (cmd_bit_cnt) to 1bit, mosi bit (mosi_bit_cnt) to 24bits. 0x04 set to 1, 0x08 set to 0x12345678 (we set data length to 24bits, so spi will only send 0x345678 in 0x78, 0x56, 0x34 order).

Example: set 0x08 to 0x12345678, call “mem 0x10000b08 0x12345678”

Now, the data registers are all ready, we need to tell SPI master pump the data to physics wires. Three steps:

1. enable chip select for spi 1. (0x38 register set to 0x02)
2. start transfer. (0x00 register spi_master_start bit:8)
3. wait data transfer done. (0x00 register spi_master_busy bit:16)
4. disable chip select spi 1. (0x38 register set back to 0)

After this, you will find the same wave as my upper picture.
Looks like everything works smoothly, I should send the commands as ILI9488 datasheet described then everything should work.

But…shit always happening. I find a weird bug on ILI9488 screen 😅  have to stop there a long time and try to detours that weird bug. I will explain on my next blog.😘