I modified the OpenMDUV380 source code so whenever backlight is turned off, the screen enters the deep stand-by mode (as described in page 100 of the HX8353-E datasheet), and I'm posting it here in case anyone finds it interesting.
I haven't measured (yet) how much current is saved by turning on this deep stand-by mode. Also, minimum brightness should be set to 0%, because if backlight is still on while the screen is in sleep mode, it just appears grey. I haven't prepared the code for this case because in my version of the firmware I removed the minimum brightness option altogether, but it's just a matter of adding an "if" clause so if the user selected a minimum brightness, the display is not put into deep stand-by mode.
A future improvement could be setting a timer to sleep the screen after backlight has been turned off for several seconds, or when the Eco mode kicks in (that would prevent the screen from being turned on and off repeatedly, unless it hasn't been touched for a while, but I'm not sure if this is really necessary as the screen only takes about 30 ms to wake with this modification).
The implementation is as follows:
First I changed the displayEnableBacklight function in display.c
Code: Select all
void displayEnableBacklight(bool enable, int displayBacklightPercentageOff)
{
if (enable)
{
if ((!displayIsBacklightLit()) && dispInitialised)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
// Display shares its pins with the keypad, so the pind need to be put into alternate mode to work with the FSMC
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_FSMC;
GPIO_InitStruct.Pin = LCD_D0_Pin | LCD_D1_Pin | LCD_D2_Pin | LCD_D3_Pin;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LCD_D4_Pin | LCD_D5_Pin | LCD_D6_Pin | LCD_D7_Pin;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET);
{
uint8_t opts[] = { 0x01 };
displayWriteCmds(HX8583_CMD_SETPWCTR, 1, opts);
}
vTaskDelay((25 / portTICK_PERIOD_MS));
{
uint8_t opts[] = { 0x00 };
displayWriteCmds(HX8583_CMD_SETPWCTR, 1, opts);
}
displayWriteCmd(HX8583_CMD_SLPOUT);
displayWriteCmd(HX8583_CMD_DISPON);
HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET);
displayRenderRows(0, DISPLAY_NUMBER_OF_ROWS, true);
vTaskDelay((10 / portTICK_PERIOD_MS));
}
displaySetBacklightIntensityPercentage(nonVolatileSettings.displayBacklightPercentage);
}
else
{
displaySetBacklightIntensityPercentage(displayBacklightPercentageOff);
GPIO_InitTypeDef GPIO_InitStruct = {0};
// Display shares its pins with the keypad, so the pind need to be put into alternate mode to work with the FSMC
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_FSMC;
GPIO_InitStruct.Pin = LCD_D0_Pin | LCD_D1_Pin | LCD_D2_Pin | LCD_D3_Pin;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LCD_D4_Pin | LCD_D5_Pin | LCD_D6_Pin | LCD_D7_Pin;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET);
displayWriteCmd(HX8583_CMD_DISPOFF);
displayWriteCmd(HX8583_CMD_SLPIN);
{
uint8_t opts[] = { 0xff, 0x83, 0x53 };
displayWriteCmds(HX8583_CMD_SETEXTC, 3, opts);
}
{
uint8_t opts[] = { 0x01 };
displayWriteCmds(HX8583_CMD_SETPWCTR, 1, opts);
}
{
uint8_t opts[] = { 0x03 };
displayWriteCmds(HX8583_CMD_SETPWCTR, 1, opts);
}
HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET);
}
}
NOTE 2: the 25 ms delay is indicated in the datasheet (it says >20ms delay, but only 20 ms didn't work properly to me). The other 10 ms delay is to give a bit of time to the screen to properly turn on, as if that delay is removed, a white screen can be seen for a short time (and when using dark themes is quite noticeable). Maybe this second delay could go before rendering the display, but it's working fine as it is.
I also had to modify the displayRenderRows in HX8353E.c so the the display is not rendered while it's off. The menus, UI's, etc. will still update the screen buffer, but the buffer will only be sent to the display when it has been turned on from sleep but before turning on backlight. So, when backlight is off, displayRenderRows does not send any data to the display. I added another input to the function to bypass this restriction (because when the screen is turned on from sleep mode, it has to be rendered before backlight is turned on, so the user doesn't see weird things on screen).
Code: Select all
void displayRenderRows(int16_t startRow, int16_t endRow, bool forceRender)
{
if (displayIsBacklightLit() || forceRender)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
// Display controller has 8 lines per row.
startRow *= 8;
endRow *= 8;
// Display shares its pins with the keypad, so the pind need to be put into alternate mode to work with the FSMC
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_FSMC;
GPIO_InitStruct.Pin = LCD_D0_Pin | LCD_D1_Pin | LCD_D2_Pin | LCD_D3_Pin;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LCD_D4_Pin | LCD_D5_Pin | LCD_D6_Pin | LCD_D7_Pin;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET);
// Set start and end rows of the transfer
{
uint8_t opts[] = { 0x00, startRow, 0x00, endRow };
displayWriteCmds(HX8583_CMD_RASET, sizeof(opts), opts);
}
displayWriteCmd(HX8583_CMD_RAMWR);
uint8_t *framePtr = (uint8_t *)screenBuf + (DISPLAY_SIZE_X * startRow * sizeof(uint16_t));
//if (HAL_DMA_RegisterCallback(&hdma_memtomem_dma2_stream0, HAL_DMA_XFER_CPLT_CB_ID, dmaCompleteCallback)== HAL_OK)
{
HAL_StatusTypeDef status = HAL_DMA_Start(&hdma_memtomem_dma2_stream0, (uint32_t)framePtr, LCD_FSMC_ADDR_DATA, (endRow - startRow) * DISPLAY_SIZE_X * sizeof(uint16_t));
if (status == HAL_OK)
{
HAL_DMA_PollForTransfer(&hdma_memtomem_dma2_stream0, HAL_DMA_FULL_TRANSFER, HAL_MAX_DELAY);
// need to wait for completion otherwise we CS gets disabled immediately.
// This could be done using a transfer complete callback
}
}
/*
// fallback
for(int y = 0; y < (endRow - startRow) * DISPLAY_SIZE_X * sizeof(uint16_t); y++)
{
*((volatile uint8_t*) LCD_FSMC_ADDR_DATA) = *framePtr++;
}*/
HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET);
*((volatile uint8_t*) LCD_FSMC_ADDR_DATA) = 0;// write 0 to the display pins , to pull them all low, so keyboard reads don't need to
}
}
I implemented it in the only MD-UV3x0 release available to date, if this functions have been changed for the last betas, I don't know if it'll work.
I'll do some testing to check how much power this saves (I read somewhere in the forum that the new platforms use more current than the GD77-like platforms, so maybe this helps a bit), and also to see if any issues have been creating when RXing a signal with the screen off (but I don't think there will be any issues, as the function gives 10 ms for the screen to properly turn on before displaying anything).
Anyway, hope this helps.
73