The JN5168 chip itself has only 5 PWM outputs and thus is not able to control more than one RGB LED strip. To overcome this I want to connect an Arduino Mega to the JN5168. The Mega has 15 PWM outputs so up to 5 RGB strips can be connected. To connect the two devices I chose to use the standard UART serial interface that is activated by default in the NXP demos. In this post I will describe how to connect the two devices and what to do to make the Arduino understand commands from the JN5168.
Hardware serial connection from JN5168 to the Arduino
As the Arduino is using 5V level on the serial connection and the JN5168 is using 3.3V a logic level converter (LLC) has to be used. This little device connects the two serial interfaces shifting from 5V to 3.3V. The connection can be seen in the following image (to drive the JN5168 from the Arduino connect an additional wire from the 3V3 pin of the Arduino to PIN 17 of the JN5168):
Software serial connection from JN5168 to the Arduino (JN5168 program)
I used the default UART port of the JN5168 because of two reasons:
- It is activated by default and the demos are already making use of the output
- I didn’t connect any additional wires than the ones that need to be connected to flash the chip and use the PWM output and the default UART is also used to flash the firmware
To have a more stable connection to the Arduino I reduced the baud rate from 115600, which is the default rate, to 9600 which the Arduino can handle better. To do this in the file app_start_light.c go to the function vAppMain() and search for the line :
and change it to:
Do the same in the function vInitialiseApp() in the same file.
I tried two different approaches to send output to the arduino:
- Use the debug output of the TRACE_LIGHT_TASK / DEBUG_LIGHT_TASK
- Define a custom debug flag to directly output the PWM signal.
As I didn’t have success yet creating multiple RGB endpoints and am waiting for PeeVeeOne to publish his work on multiple endpoints, I first went with option 2 which is currently not able to hand over an identifier for the endpoint which the option 1 is able to. The second option has the advantage that it handles smooth transitions, which the other one doesn’t. Once I am able to create more endpoints I may create another output. I will describe both solutions anyway:
Option 1: TRACE_LIGHT_TASK
First, activate the debug flag in the Makefile:
CFLAGS += -DDEBUG_LIGHT_TASK
Then go to the file app_zcl_light_task.c and search for
I modified the first appearance (in APP_ZCL_cbEndpointCallback) of the function, where it outputs a new line and the RGBL (Red, Green, Blue, Level) values to include an identifiying symbol (§) and the endpoint:
DBG_vPrintf(TRACE_LIGHT_TASK, "\n§ EP %d R %d G %d B %d L %d ", psEvent->u8EndPoint, u8Red, u8Green, u8Blue, sLight.sLevelControlServerCluster.u8CurrentLevel);
There is a second appearance in the same file and the same function (APP_ZCL_cbEndpointCallback ) where I did the same thing again.
In the file App_Light_ColorLight.c there are two other usages of the function which handle the identification effect. In the function APP_vHandleIdentify() there is currently no handle for the endpoint available so I didn’t modify this one. In the vIdEffectTick() there is an endpoint reference available so I added this similar to the function call above.
DBG_vPrintf(TRACE_LIGHT_TASK, "§ EP %d R %d G %d B %d L %d Hue %d Sat %d\n", u8Endpoint, u8Red, u8Green, u8Blue, sLight.sLevelControlServerCluster.u8CurrentLevel, sLight.sColourControlServerCluster.u8CurrentHue, sLight.sColourControlServerCluster.u8CurrentSaturation);
In the end the Arduino will receive a message will look like this:
§ EP 10 R 255 G 227 B 139 L 147 Hue 0 Sat 0 X 24939 Y 24701 M 1 On 1 OnTime 0 OffTime 0
This one call will result in 10 PWM changes in the JN5168 to have a nice transition. This is why I currently go with the second option:
Option 2: TRACE_PWM
First, I defined and enabled a new debug flag in the Makefile:
CFLAGS += -DDEBUG_PWM
Then in the file DriverBulb_JN516X_RGB.c I added the following to the definition section at the beginning:
#ifdef DEBUG_PWM #define TRACE_PWM TRUE #else #define TRACE_PWM FALSE #endif
Then, in the function DriverBulb_vOutput() I added the following after the calls to vAHI_TimerStartRepeat at the end:
#if TRACE_PWM DBG_vPrintf(TRACE_PWM, "\n# EP %d On %d R %d G %d B %d L %d", (uint8)10, bIsOn, u8Red, u8Green, u8Blue, u8CurrLevel ); #endif
Together with the first option this will result in the following output (as I said it produces a smooth transition):
§ EP 10 R 255 G 227 B 139 L 147 Hue 0 Sat 0 X 24939 Y 24701 M 1 On 1 OnTime 0 OffTime 0 # EP 10 On 1 R 170 G 151 B 92 L 170 # EP 10 On 1 R 167 G 148 B 91 L 167 # EP 10 On 1 R 165 G 146 B 89 L 165 # EP 10 On 1 R 162 G 144 B 88 L 162 # EP 10 On 1 R 160 G 142 B 87 L 160 # EP 10 On 1 R 157 G 139 B 85 L 157 # EP 10 On 1 R 154 G 137 B 83 L 154 # EP 10 On 1 R 152 G 135 B 82 L 152 # EP 10 On 1 R 149 G 132 B 81 L 149 # EP 10 On 1 R 147 G 130 B 80 L 147
You can also see that the RGB values changed. This is according to the level value. The calculation is:
/* Scale colour for brightness level */ u8Red = (uint8)(((uint32)u8CurrRed * (uint32)u8CurrLevel) / (uint32)255); u8Green = (uint8)(((uint32)u8CurrGreen * (uint32)u8CurrLevel) / (uint32)255); u8Blue = (uint8)(((uint32)u8CurrBlue * (uint32)u8CurrLevel) / (uint32)255);
The level is not really necessary in the output because the RGB values are already adjusted. I kept them anyway.
Software serial connection from JN5168 to the Arduino (Arduino program)
For the Arduino part I first setup the serial connection (I connected it to Serial2) and read the input. Based on the first character (§ or # are the relevant ones for the two options) the program decides whether the whole line is relevant.
Then it parses the input line using the function strtok(). Then I set the PWM using analogWrite(pin, value).
The serial input is lagging sometimes (though I think this is only the case when using the serial output to the other serial port) so garbage is getting read as a line. In case of not set values I checked whether the value is correctly set. Otherwise the old value is used. This may lead to wrong values but better than nothing.
My currently used Arduino sketch (using only one PWM output) can be downloaded here:
This may not be the best way of communication (SPI may be better) but it is the easiest to setup. To command 4 separate endpoints I may have to use option 1 and go without transitions or implement them myself on the arduino. The bottle neck seems to be the serial connection as the arduino seems to be too slow to process the serial input fast enough. This is another argument for option 1 as it sends fewer lines. Although it is sending more than one line for a simple light change, too. Maybe the app itself also sends several commands to have a nice transition. I may check this later on. In any case I recommend disabling all other debug outputs to make better use of the serial communication and loose fewer lines.
Currently I am also building a board to connect everything together. It will not be very professional (as I will be using many jumper wires instead of connecting everything directly but I want to be flexible) but should work for me. It will be hidden away anyway. The board connected to the Arduino and the serial connection to the JN5168 can be seen in the upper left with one temporarily connected RGB strip. In the final version they will be connected with screw terminals. The LLC will also go from the breadboard to the custom board.
This is the current progress with connections ready for two RGB strips.
There will be 4 RGB connections in the final version to be connected with screw terminals, the LLC and a connection for an external power source. This is all still work in progress so I will publih the final schematics when I am ready and know that everything is working as expected. And of course I hope that the weather will be getting better here so I can disassemble our night desks and get them to my workbench (actually my balcony which is why I am hoping for good weather 😉