Category Archives: VoCore

VoCore2: Use more ethernet

Default VoCore2 only has one ethernet enabled, it is ethernet port0. But actually VoCore2 has 5 ethernet ports. This blog is talking about how to enable them.

First, let’s check the hardware connection.

One RJ45 with transformer and one 100nF are enough to make one ethernet port work.

Second, we need to enable ports in kernel level.

This is controlled by register 0x1000003c. In client mode, we can simply use “mem 0x1000003c 0xe001ff” to setup it, or you can use hard way to enable this by device tree.

Once you finish second step, when you plug in or plug out the ethernet cable, you will find a kernel log like “rt3050-esw 10110000.esw: link changed 0x00”;

Port0 plug in: “rt3050-esw 10110000.esw: link changed 0x01”;

Both Port0 and Port2 plug in: “rt3050-esw 10110000.esw: link changed 0x05”

PS: once you enable more than one ethernet, debug port UART2 will be disabled, you will need to change it to UART0/UART1 in VOCORE2.dtsi/VOCORE2.dts; also SDMMC port for SD card is disabled either, please check blog and for tutorial about using 5 ethernet ports and SD card same time.

Third, we need to setup in OpenWrt to enable them

I am not very good at this part, looks like default OpenWrt setting is enabled that two ports, Port0 and Port2, but actually we only have one ethernet by default hardware(VoCore2 Ultimate). So if you only need to use two ports and the ports happens to be Port0 and Port2, you do not need change anything.

If you need to use other ethernet port like ethernet port1, port3, port4, you will need to setup /etc/config/network. Maybe also need to enable them in device tree. This part I am still learning, now I am trying different connection to understand virtual lan, later I will write another blog talk about my learning process. Any suggestions are warm welcome, please email to me(a) or support(a)

VoCore2: Force Write to Read-Only MTD Partition

When I make a test jig for a project, I need to write new uboot to cover old one. Normally I will use uboot UART to update uboot partition, that is the fastest way, we do not have to wait Linux system ready, but it has a failure rate because UART is not very stable.

Currently I need to login to Linux and run test application. I do not have to upload from UART anymore, but same time, I just found u-boot partition is default read-only. This is locked in VOCORE2.dts at compile stage to avoid user erase uboot by mistake. If we need to overwrite u-boot, we can not modify it directly but have to upgrade the firmware who has a writeable u-boot partition.

If I upgrade the firmware, it will take too much time, at least 2 minutes…not acceptable for mass production. For that reason, I am thinking, is that possible we hack the kernel and remove the READ-ONLY tag from mtd partition without do change to firmware?

Lucky, that is possible, and pretty simple to do.

mtd driver has a structure named mtd_info to store every detail of a mtd partition. It is using a flag named MTD_WRITEABLE to determine whether a mtd partition is readonly or not.

Reference: linux-4.14/drivers/mtd/ofpart.c

	if (of_get_property(pp, "read-only", &len))
		parts[i].mask_flags |= MTD_WRITEABLE;

Now, just need to find a way add that MTD_WRITEABLE flag to mtd partition.

We can not do it in user mode, because kernel mode memory is protected. So I write a small driver for it.

#include <linux/init.h>
#include <linux/module.h>
#include <linux/mtd/mtd.h>

int w2uboot_init(void)
    struct mtd_info *mtd;
    mtd = get_mtd_device_nm("u-boot");
    mtd->flags |= MTD_WRITEABLE;
    printk(KERN_INFO "unlock u-boot, now it is writeable\n");
    return 0;

void w2uboot_exit(void)



Compile and insert this module to kernel. Magically, the u-boot is unlocked. Now we can use mtd -e u-boot write uboot.bin u-boot write to uboot partition.

To compile the code(save as w2uboot.c), try this way in same folder:

echo 'obj-m=w2uboot.o' > Makefile
make -C [path to linux]/linux-4.14.195 M=$(PWD) CROSS_COMPILE=mipsel-openwrt-linux- ARCH=mips

VoCore2 + Bluetooth

Recently a lot of chip shortage, really makes me headache. ๐Ÿ™‚

This is a bluetooth module works with VoCore2, it is based on CSR8510.

PS: Qualcomm is really a suck company. I can not get any documentation from them but have to find some leak ones online…

Lucky thing, this CSR8510 is almost working out of box. No idea what that EEPROM used to do, I just use an empty EEPROM, this device still work normally.

So connect it to VoCore2 USB host port, then remember install bluez-daemon in VoCore2, it just works.

We can use hciconfig / hciconfig hci0 to show this device.

And to make it work, call hciconfig hci0 up

Or scan nearby device by hcitool scan

Or ping the nearby device to make sure everything is normal: l2ping xx:xx:xx:C1:58:C2

Finally. here it is ๐Ÿ™‚

the little device ๐Ÿ™‚

MT76: Learningโ€ฆ3

Finally my patch has into main branch of mt76 ๐Ÿ™‚ now we have stable official supported wireless driver, and ADHOC, MESH are default supported too.

My patch link is here:

Thanks the admin, make it in better format:

Next blog, I will try mesh and adhoc mode, check if they work.

Be Careful when Buy from

When I make samples, I prefer for a long time, but now, I can not recommend it anymore, because buy from them are pretty risky.

PS: for mass production, normally we directly order from parts factory, not such provider.

First Story

Around 2 years ago, 2017, I was working on POE version of VoCore2, I used a SMT electrolytic capacitor (22uF, 63V). From its datasheet, max allowed temperature is 260C 10seconds, but after my standard reflow(260C 6 seconds), 80% of that caps were become “popcorn”… lucky me, not exploded.

I contacted their sales and they sent me the replacement — even the total value was just 2USD but I spent over 5 hours to fix the samples — I was still happy.

Second Story

Just a few days ago, I bought some parts from them again. The BOM list was pretty long and I made a mistake, I chose wrong type of a SIM card slot because they really looks same…I found it out only when I received them. I contacted in first time, hoped they can replace them, but guess what? They refused! Because they said they have rules that they refuse return parts even the package is not opened and not used at all.

That was a big surprise for me. And wrong parts are useless for me, it is a waste…

PS: its type is C99403, SIM-01A, 70pcs, if you want it, just contact me, I will send them to you free, just need postage ๐Ÿ™‚

I still negotiate with them. This is not fair, in any country of the world. We all make mistakes, if we can not return wrong package, who dare to buy from internet?

So finally, if you use too, just be very careful, because they do not allow return package even the package is not opened.

I am pretty unhappy with them this time, because there is no warning show on their site from begin to end. Even now, I still can not find such warning or rule on their site. Somebody told me that is really in their site somewhere but in a pretty small font…^_^?

Anyway, for such chip provider, just be careful and careful. You can not make any mistake when you put your order on them. I paid the school fee and now I know. ๐Ÿ™‚

VoCore2: OpenWrt 19.07.3 Firmware

Now official OpenWrt 19.07.3 firmware released.

Link: (For VoCore2)

Link: (For VoCore2 Ultimate)

Different is VoCore2 Ultimate has embed SD card driver, for VoCore2 do not have SD card slot, it will show a lot of junk message to the system log.

Embed software:

  • LuCI
  • mem (for /dev/mem access)

Support interface:

  • SD Card (V2U)
  • Ethernet
  • WiFi
  • I2C
  • I2S
  • GPIO
  • Reference Clock
  • SPI
  • USB 2.0 HS Host

MT76: Learningโ€ฆ2

After read the mt76 source code, I find the source code miss eerpom 0x34 setting (not a real eeprom, just flash factory partition), and 0x34 is used to choose antenna number…

So fix is pretty simple:

--- a/mt7603/init.c
+++ b/mt7603/init.c
@@ -277,6 +277,9 @@ mt7603_init_hardware(struct mt7603_dev *dev)
        if (ret < 0)
                return ret;
+       if (((u8*)dev->[MT_EE_NIC_CONF_0] == 0x11)
+               dev->mphy.antenna_mask = 1;
        ret = mt7603_dma_init(dev);
        if (ret)
                return ret;

Once we find 0x34(MT_EE_NIC_CONF_0) is 0x11, force the driver use one antenna. That’s all.

Now after over 1 hour test, this mt76 driver is working very well and stably at >= 52Mbps 1T1R.

MT76: Learning…

Develop on a chip like MT7628 is full of adventure…For new version of firmware I plan to use opensource MT76 driver instead of MT7628 driver. Weird thing is MT76 works well on some devices, but not well on some others, include VoCore2.

I guess it is antenna issue, because for normal WIFI4 routers default has two antennas works at same time for 300Mbps, 802.11n mode; but for VoCore2, default antenna 2 is disabled to save power and avoid cross talk when no second antenna attached.

Thanks to github MT76 contributors, I have some clues to fix this:

After apply that patch, change mt76-2020-03-10-08054d5a/mt7603/init.c line 538

- dev->mt76.antenna_mask = 1;
+ dev->mt76.antenna_mask = 3;

I get a good result, 5minute no disconnect anymore.

[  5] 297.00-298.00 sec  6.31 MBytes  52.9 Mbits/sec                  
[  5] 298.00-299.00 sec  6.38 MBytes  53.5 Mbits/sec                  
[  5] 299.00-300.00 sec  6.41 MBytes  53.7 Mbits/sec                  
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-300.00 sec  1.75 GBytes  50.2 Mbits/sec                  sender
[  5]   0.00-300.07 sec  1.75 GBytes  50.2 Mbits/sec                  receiver
It stay at MCS Index: 7, do not jump to MCS Index: 15, so the two antennas will not crosstalk to each other, now we have stable result.

So this should be the solution, just need test more. Currently we store 1T1R and 2T2R parameter to factory setting partition in flash, so there are two ways, one is to add factory setting patch to change it, another is to add DTS setting patch to change it, emm, which way is better? hard choice.

To be continue…

VoCore2 + Touch + LVGL DEMO

LVGL new demo looks better

Here is the compressed firmware link, upgrade then it is able to work directly ๐Ÿ™‚ Just need two files to work, one is the fbusb.ko driver for touch and USB data transfer, another is /root/demo which is the littlevgl demo application.

New Screen with touch API is simpler, please check for more details.

VoCore2 SPI: full duplex

mt7628a has a wafer/silicon bug on SPI, we can not use its SPI in full duplex mode, but we can use bitbang for that mode. For some device do not support half-duplex, maybe this is the only way.

To enable bitbang on VoCore2, we need to modify Linux kernel code, VOCORE2.DTS and kernel setting.

Setup Kernel Setting

  1. call “make kernel_menuconfig”
  2. In menu, select “Device Drivers” => “SPI Support” => <*> ย  GPIO-based bitbanging SPI Master


This file is in target/linux/ramips/dts, example of the DTS. We need to set the driver to “spi-gpio” and pinctrl set the pins to GPIO mode.


#include "VOCORE2.dtsi"

#include <dt-bindings/gpio/gpio.h>

/ {
	compatible = "vocore,vocore2", "mediatek,mt7628an-soc";
	model = "VoCore2";

	gpio-leds {
		compatible = "gpio-leds";

		status {
			label = "vocore2:fuchsia:status";
			gpios = <&gpio1 12 GPIO_ACTIVE_HIGH>;

	spi1: spi-gpio {
		status = "okay";

		compatible = "spi-gpio";

		gpio-sck = <&gpio0 7 1>;
        	gpio-miso = <&gpio0 9 1>;
        	gpio-mosi = <&gpio0 8 1>;

        	cs-gpios = <&gpio0 10 1>, <&gpio0 6 1>;
        	num-chipselects = <2>;

&pinctrl {
        state_default: pinctrl0 {
                spi {
                        ralink,group = "spi";
                        ralink,function = "gpio";
                spi_cs1 {
                        ralink,group = "spi cs1";
                        ralink,function = "gpio";

&i2c {
	status = "okay";

&spi1 {
	m25p80@0 {
		#address-cells = <1>;
		#size-cells = <1>;
		compatible = "jedec,spi-nor";
		reg = <0>;
		spi-max-frequency = <10000000>;
		m25p,chunked-io = <32>;

		partition@0 {
			label = "u-boot";
			reg = <0x0 0x30000>;

		partition@30000 {
			label = "u-boot-env";
			reg = <0x30000 0x10000>;

		factory: partition@40000 {
			label = "factory";
			reg = <0x40000 0x10000>;

		partition@50000 {
			label = "firmware";
			reg = <0x50000 0xfb0000>;

	spidev@1 {
		#address-cells = <1>;
		#size-cells = <1>;
		compatible = "rohm,dh2228fv";
		reg = <1>;
		spi-max-frequency = <10000000>;

Patch Linux spi-gpio.c

This is because CS1 pins has a default pull low resistor. If we do not patch it, CS1 will be low at startup, conflict with the flash driver who use CS0. So we must at startup setup CS1 pin to output and value to high.

                if (!SPI_N_CHIPSEL)
                        spi_gpio->cs_gpios[0] = SPI_GPIO_NO_CHIPSELECT;
                        for (i = 0; i < SPI_N_CHIPSEL; i++) {
                                status = of_get_named_gpio(np, "cs-gpios", i);
                                if (status < 0) {
                                                "invalid cs-gpios property\n");
                                        goto gpio_free;
                                spi_gpio->cs_gpios[i] = status;

+                               gpio_request(status, dev_name(&pdev->dev));
+                               gpio_direction_output(status, 1);
+                               gpio_free(status);

        spi_gpio->bitbang.master = master;
        spi_gpio->bitbang.chipselect = spi_gpio_chipselect;

That is all ๐Ÿ™‚ Now the firmware is able to support SPI device in full duplex mode.