Di2 Electronic shifting bike groupset upgrade

My road bike is a 2013 Merida Scultura Comp 905, with an electronic shifting compatible carbon frame and the 10-speed Shimano Ultegra 6700 groupset and rim brakes. I recently purchased the Ultegra 8050 groupset and, in this post, I describe the steps that were needed to install on the frame and some observations based on the experience.

But first of all, since I have changed already some components from the stock Scultura 905, the before-after components for the changes from mechanical groupset to electronic groupset are shown in the table below

Component Original Upgraded
Front Derailleur FD-6700 FD-R8050
Rear Derailleur RD-6700 RD-R8050-SS
Chainset 6750 50/34 R8000 50/34
Cassette CS-6700 11/28 CS-R8000 11/28
Shifters ST-6700 ST-R8050
Brakes Merida Pro BB-R8000
Seatpost Deda Elementi Superleggero 27.2mm [same]
Wheelset Fulcrum Racing Comp Fulcrum Racing Zero Black
Chain Ultegra 6700 10-speed CN-HG601
Bottom bracket Ultegra 6800 [same]
Battery - BT-DN110-A
Junction boxes - SM-EW90-A (frame) and SM-JC41 (internal)
Wireless unit - EW-WU111

The components already changed aided the electronic shifting upgrade:

  • The original seatpost (Merida Carbon) was broken in 2018 and replaced with the Deda Elementi one. It supports the internal battery using seatpost battery holder 
  • The chainset (FSA Energy Mega 50/34) was broken in 2018 and replaced with the Ultegra compact equivalent. I changed the bottom bracket at the same time from the FSA Mega Exo to the Shimano 6800 one. This ensures compatiblity with the updated chainset.

Some more components to consider, which were used for the installation and operation:

  • Deda seatpost battery holder: Needed to mount the battery inside the seatpost. You could make something custom, but this is pretty neat.
  • EW-SD50 wires: Various lengths, depending on the frame size and location of each of the components.
  • SM-GM01 and SM-GM02 grommets: Used to secure the wires when entering the frame.
  • SM-AD91 band adapter: Needed if the frame doesn't have a front derailleur hanger
  • EW-SD501 wire holders: Place on the wires that are routed inside the frame. Prevents rattling noise and helps you keep your sanity.
  • Concerning the wheels, the hub was only 10-speed compatible, so an upgrade was needed :)
  • The wireless unit is not mandatory, but it allows to connect the di2 mechanism to the GPS head unit. This function is used to check the current battery and gear combination, as well as to control the head unit from the shifters.

 Here is the bike at its mechanical shifting state, together with all of the components. Logistics to get all the compatible parts is not the easiest part in the world.

Before starting to route cables through the frame, it is a good idea to check that all of the components are working with the intended connections, on the bench (or table). I connected the wireless transceiver between the top and bottom junction box and upgraded the firmware of all the components.

There is a junction box that goes next the bottom bracket. I also placed the wireless transceiver next to it and packaged it to avoid any rattling inside the frame. Although Shimano does not recommend placing the transceiver inside the frame, I haven't had any connection issue with the head unit or phone. Because of all the various connections inside this tight space, I labeled all the cables, in case modifications/troubleshooting are need in the future.

The rear derailleur is easy to fit. However, it is difficult to make the grommet stay in place. It needs some patience. The high and low screws need to be setup (as is the case with a mechanical derailleur). However, the "cable tension" is setup electronically.

Shimano has very detailed diagrams on how to assemble the front derailleur with a band adapter (my frame doesn't have a derailleur hanger). I didn't need to do any adjustment after that.

I placed the junction box underneath the stem, with some velcro tape. Though I haven't needed to remove the junction box yet and don't think I will anytime soon. However, I didn't like Shimano's solution with the elastic band (I find it ugly). However, if you were to ride on cobblestones, perhaps this would be the only solution. I used heatshrink to increase a bit the the width of the Di2 cable and fit it between the junction box and the frame.

As I wanted to get extra buttons to shift the rear derailleur from the top instead of the hoods, I modified some buttons from eBay with the Di2 connector (cut a Di2 cable in half and soldered it to the end of the flexi of the button, and then applied hot glue). This can be connected to sprint shifter port of the Di2 shifters.

Finished result:

Not needing to adjust the cable tension every now and then is nice. As you lose the feedback on the shifter to understand at which point of the cassette you are, it is beneficial to have the current value on the head unit. It also provides audible feedback when you reach either limit of your gearing. Concerning battery, you forget to charge it (although it alerts you when the Di2 battery is getting low). Concerning traveling, I'd argue that it is easier to disassemble the bike (I leave the battery inside the seatpost and disconnect the cable, I also disconnect the two cables from the shifters to the junction box).


Desk clock based on an STM32 microcontroller

Based on my initial tests of Dot Matrix displays using either an FPGA or an STM32F4 microcontroller, I wanted to build a desk clock with the following features:

  • Low drift using an external crystal
  • Automatic setup using an NTP server via WiFi
  • Support for daylight saving
  • Temperature and Humidity measurement
  • Periodic update using an NTP server
  • Adjustable brightness
  • Single 5V supply
  • Minimum external components and wire connections
  • Support for WiFi credentials reconfiguration

The Dot Matrix display I selected was a 64x32 RGB display which has a 5V supply input. The microcontroller I used was an STM32F767 which has a maximum clock frequency of 216MHz (important, since, as analyzed in previous articles, to achieve a high refresh rate, a high clock frequency is needed, especially as a microcontroller would be used instead of an FPGA, to keep the cost low).

The F767 is mounted on a Nucelo144 board. I selected the specific board because it had an on board 32.768kHz crystal as well as the necessary 3.3V regulator. A lower cost F4 Nucleo could also be used, but I also wanted to check some other features of the specific board (especially the hardware double precision FPU and the Ethernet PHY).

To get the time from an NTP server, I used a Wemos D1 mini board, which uses the well known ESP8266 chip. Again, the D1 mini board has a 3.3V regulator, a UART to USB converter, a USB port as well as the necessary pull up resistors for the ESP8266. I have used the ESP8266 before, when I built WiFi Power switch. The chip can be programmed through Arduino (using all the available Arduino libraries as well).

Concerning the temperature and humidity measurement (which was a late request), I selected the DHT21 (AM2301) single wire temperature and humidity sensor, which I have also used before when building the Raspberry Pi Meteo Station. It has a very good accuracy for the application, and, because of its popularity, many libraries are already available.

The connection diagram of the different components is shown below. The external 5V power supply (4A maximum current, <1A expected during operation), powers both the Dot Matrix Display as well as the Nucleo board, via the external 5V Vin pin. Through the Nucleo connectors, the 5V rail is also supplied to the Wemos D1 mini board, and is stepped down to 3.3V through the onboard regulator. 3.3V is also supplied to the DHT21 sensor via another Nucleo header connector.

Concerning data transmission, the microcontroller and the ESP8266 will communicate via UART using a predefined protocol. In case of connection loss, the STM32 microcontroller will be able to reset the ESP8266 chip via the external reset pin, which is connected to an STM32 GPIO. The temperature sensor is also connected to the ESP8266 board, to decrease any processor load of the main STM32 microcontroller (which could result in display flickering if not taken into account). What is more, the matrix display data is sent through the GPIO peripheral of the microcontroller (13 pins in total) based on code analyzed previously.

The algorithm of the microcontroller also features

  • 1 second interrupts (via the WakeUp RTC function) to update the display
  • RTC alarm interrupt to get new NTP date and time
  • Reset of the WiFi chip if no data is sent back
  • Adjustable display brightness using the Nucleo User button
  • UART interrupts for received data and error checking

The ESP8266 handles the WiFi connection (and update of credentials), temperature and humidity data from the DHT21 sensor, NTP time requests as well as daylight savings settings. To implement all of the above, the following libraries were used:

The data display format was based on a Bluetooth FPGA Dot matrix clock. In that case, each frame was constructed through a Matlab script and sent via Bluetooth to a Xilinx FPGA. As shown previously, the FPGA, because of its parallel data processing, can achieve higher color resolution (or higher FPS). However to operate, it would always need to be connected to a computer. The display features greek font support, hour and minute vertical bars (left and right side of the display respectively), a seconds bar on the bottom edge of the display as well as color animations.

The mounting on the clock was also based on the above FPGA clock. The aim of the assembly was to eliminate any wires which would interconnect the four main components. All the wires are sandwiched between the Nucleo board on one side and the dot matrix display on the other side of the mount. The user button is accessible from the backside to change the display brightness, as well as the reset button. The micro-USB ports of the Nucleo board as well as the Wemos D1 mini board are also accessible for future firmware updates.

STM32 Dot Matrix Display

Continuing on the previous work on driving a Dot Matrix Display with an FPGA, the same concept was used to connect an STM32 Discovery board to drive the display. Again, a UART bluetooth module would get data from a server and display it on the matrix.

The Board that was used is an STM32F429 Board. It features a moderately high frequency of 180MHz (top of the line STM32F7 boards have a frequency of 216MHz). However, stil, for such a task, it is low clock, since, compared to FPGAs, all the code is sequential as it will be shown below.

To drive the 64x43 pixel RGBdisplay the following signals need to be supplied:

  • Four signals which select the row couple (0-15).
  • Three signal couples (RGB1 and RGB2) which select if each LED will be activated or not.
  • A clock signal for the shift register.
  • A latch enable signal for the shift register.
  • An output enable signal.

The GPIO peripherals of the STM32 microcontroller were used. The display operates by driving each row (or more precisely each high/low pair row) individually, using 64 shift registers. After that, the next row pair is driven. In order for this refresh procedure to be invisible to the naked eye, the clock frequency needs to be high. With a PLL clock of 200MHz, a refresh rate of 120FPS were achieved using an FPGA, with 8 bit per color and 64x32 resolution. However, this PLL frequency is even higher than the CPU frequency, meaning the CPU cycle time. As a result, even with such an advanced microcontroller, the refresh rate won't be nowhere as near as the one that was achieved with the FPGA.

The complete code for this project can be found on Github. Other than the GPIO peripherals, the microcontroller uses the UART peripheral to get new data. Since the UART baud rate is low, each transmission would be visible on the display. Since each frame is 64columns x 32rows x 3colors x8bits = 6KB, multiple frames can be stored in the on-board RAM. Pointers are used for the memory bank where the UART stores a new frame as well as for the memory bank from which the controller gets the frame to display. When a new full frame arrives from the UART peripheral, an interrupt is generate to switch banks. Since the processor is busy providing the timings for each pin of the Matrix Display, the DMA peripheral is used to store the data as it arrives from UART. The interrupt is generated by the DMA peripheral.

The timing of the different signals can be shown in the images below. As it can be observed, only about 75 frames per second can be achieved, which normally would be more than enough, since for example common VGA CRT displays have a refresh rate of 60Hz. However, since the LEDs switch off instantly, the switching of each row is visible in low frame rate. As a reult, instead of 8 bits color depth (which was the case for the FPGA driver), only 3 bits were achievable with the microcontroller. The different color depths (corresponding to different ON times can be seen as well).



Zooming in even further, the clock rate of the display is shown. The 180MHz microcontroller achieves only 1MHz of clock rate, meaning that on every shift, there are about 180 cycles. The code is not optimized, but the vast difference between this implementation and the FPGA implementation is noted.

As the row is switched from 15 to 0, each row signal switches sequentially, which is captured in the diagram. Since the OE is high during that time (meaning that the display is momentarily switched off), this is not visible.



PWM Generator on a STM32L152 Discovery

The STM32L152 Discovery is a compact board which includes an LCD display, a touch sensor (linear or four keys), a push button and two LEDs. Combining all of the above, a compact PWM generator can be made with variable frequency and duty cycle.

The LCD will display the current value to be adjusted meaning either the frequency or duty cycle of the pulse. To cycle between the two settings, the push button will be used. The values will be set using the touch sensor. Finally, the pulse will be output to the green LED in order to show the actual duty cycle (via the LED intensity). The second LED will be used to show which of the two values is currently adjusted (it will also be shown in the display).

So, the timer that will be used is TIM4 and Channel 2, in order to output the PWM pulse to the blue LED (Port PB7). A standard initialization function is first run, meaning starting the timebase, the output channel and finally connecting the channel 2 output to port PB7:

void TIM4Init()
TIM_TimeBaseInitTypeDef TIM_InitStruct;
TIM_OCInitTypeDef TIM_OCInitStruct;
GPIO_InitTypeDef GPIO_InitStructure;

TIM_InitStruct.TIM_ClockDivision = TIM_CKD_DIV1 ;
TIM_InitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_InitStruct.TIM_Period = 32000;
TIM_InitStruct.TIM_Prescaler = 1;
TIM_TimeBaseInit(TIM4, &amp;TIM_InitStruct);

TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStruct.TIM_Pulse = 100;
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC2Init(TIM4, &amp;TIM_OCInitStruct);

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOB, &amp;GPIO_InitStructure);

TIM_OC2PreloadConfig(TIM4, TIM_OCPreload_Enable);
UpdatePWM(frequency, duty);

Next, an easy backend to change the frequency and duty cycle must be used. The function UpdatePWM takes two operands (frequency and duty cycle) and appropriately configures TIM4. Since the L1 microcontroller can run in different clock frequency configurations, the "SystemCoreClock" variable used, which is set in the system source file (assuming that the APB1 Prescaler is 1):

void UpdatePWM(double frequency, double duty)
//frequency in Hz, duty 0-100.0
long int ratio;

ratio = (long)SystemCoreClock/frequency;
TIM4->PSC = (int)(ratio/0xFFFF);

ratio = ((long)SystemCoreClock/(TIM4-&gt;PSC+1));
TIM4->ARR = (int)(ratio/frequency)-1;

TIM4->CCR2 = (int)((TIM4->ARR+1)*duty)/100-1;

To update the LCD Display, the provided function LCD_GLASS_WriteChar is used for each character, whereas, a custom bargraph function is written to update the bargraph as a percentage value:

void UpdateDisplay(void)
bargraph((int) duty, 100);
if (state==FREQ) sprintf(displaystring,"f%4.2dk", (int) (10*frequency));
if (state==DUTY) sprintf(displaystring,"d%4.2d%%", (int) (10*duty));
LCD_GLASS_WriteChar((unsigned char *)displaystring + 0, 0, COLUMN_ON, 1);
LCD_GLASS_WriteChar((unsigned char *)displaystring + 1, 0, 0, 2);
LCD_GLASS_WriteChar((unsigned char *)displaystring + 2, 0, 0, 3);
LCD_GLASS_WriteChar((unsigned char *)displaystring + 3, POINT_ON, 0, 4);
LCD_GLASS_WriteChar((unsigned char *)displaystring + 4, 0, 0, 5);
LCD_GLASS_WriteChar((unsigned char *)displaystring + 5, 0, 0, 6);
void bargraph(int value, int max)
double percentage=(double)value/(double)max;
if (percentage>0.25) BAR0_ON;
if (percentage>=0.5) BAR1_ON;
if (percentage>=0.75) BAR2_ON;
if (percentage==1) BAR3_ON;

Finally, the touch sensor value is read using the provided STMTouch driver.

The full project of the PWM Generator for the STM32L152 Discovery can be found on my Github page.

15" Macbook Pro Retina Heat dissipation

Through the last 7 years I have used three unibody 15" Macbook Pro's, with the Early 2015 Retina Model the latest. The evolution of the power saving through the models and case temperature decrease is tremendous. Taking into account that the latest model is even thinner and more powerful, this is a marvelous engineering application.

Macbooks of the last ten years (apart from the fanless 12" model) use fans that feed the hot air to the front of the case, towards the display. This is mandatory, as the logic board is found below the keyboard, and the battery is positioned below the trackpad, as shown in the teardown photo of iFixit.

All 15" models have tradionally used two fans, spinning at ~2000rpm when idle. The optimization level of the heat dissipation for the Retina model, is shown by using a 2160rpm when idle for the left fan and 2000rpm for the right fan. A thermal image of the heat dissipation is shown bellow. The temperature difference between the two fans is clearly shown.