diff --git a/examples/platform/silabs/efr32/display/demo-ui.c b/examples/platform/silabs/efr32/display/demo-ui.c index 73a8d52ea71090..68b53ba5a804c9 100644 --- a/examples/platform/silabs/efr32/display/demo-ui.c +++ b/examples/platform/silabs/efr32/display/demo-ui.c @@ -25,6 +25,9 @@ #include "glib.h" #include #include +#if (defined(EFR32MG24) && defined(WF200_WIFI)) +#include "spi_multiplex.h" +#endif // Main Logo and App image #define SILICONLABS_X_POSITION ((glibContext.pDisplayGeometry->xSize - SILICONLABS_BITMAP_WIDTH) / 2) @@ -105,14 +108,26 @@ void demoUIDisplayHeader(char * name) { GLIB_drawStringOnLine(&glibContext, name, 5, GLIB_ALIGN_CENTER, 0, 0, true); } +#if (defined(EFR32MG24) && defined(WF200_WIFI)) + pre_lcd_spi_transfer(); +#endif DMD_updateDisplay(); +#if (defined(EFR32MG24) && defined(WF200_WIFI)) + post_lcd_spi_transfer(); +#endif } void demoUIDisplayApp(bool on) { GLIB_drawBitmap(&glibContext, APP_X_POSITION, APP_Y_POSITION, APP_BITMAP_WIDTH, APP_BITMAP_HEIGHT, (on ? OnStateBitMap : OffStateBitMap)); +#if (defined(EFR32MG24) && defined(WF200_WIFI)) + pre_lcd_spi_transfer(); +#endif DMD_updateDisplay(); +#if (defined(EFR32MG24) && defined(WF200_WIFI)) + post_lcd_spi_transfer(); +#endif } void demoUIDisplayProtocol(demoUIProtocol protocol, bool isConnected) @@ -123,7 +138,13 @@ void demoUIDisplayProtocol(demoUIProtocol protocol, bool isConnected) (protocol == DEMO_UI_PROTOCOL1 ? PROT1_BITMAP_HEIGHT : PROT2_BITMAP_HEIGHT), (protocol == DEMO_UI_PROTOCOL1 ? (isConnected ? PROT1_BITMAP_CONN : PROT1_BITMAP) : (isConnected ? PROT2_BITMAP_CONN : PROT2_BITMAP))); +#if (defined(EFR32MG24) && defined(WF200_WIFI)) + pre_lcd_spi_transfer(); +#endif DMD_updateDisplay(); +#if (defined(EFR32MG24) && defined(WF200_WIFI)) + post_lcd_spi_transfer(); +#endif } void demoUIClearMainScreen(uint8_t * name) diff --git a/examples/platform/silabs/efr32/display/lcd.cpp b/examples/platform/silabs/efr32/display/lcd.cpp index 6e1f2d2fe93de3..37ccb0dedbb1d5 100644 --- a/examples/platform/silabs/efr32/display/lcd.cpp +++ b/examples/platform/silabs/efr32/display/lcd.cpp @@ -31,6 +31,9 @@ #include "sl_board_control.h" +#if (defined(EFR32MG24) && defined(WF200_WIFI)) +#include "spi_multiplex.h" +#endif #define LCD_SIZE 128 #define QR_CODE_VERSION 4 #define QR_CODE_MODULE_SIZE 3 @@ -68,6 +71,12 @@ CHIP_ERROR SilabsLCD::Init(uint8_t * name, bool initialState) err = CHIP_ERROR_INTERNAL; } +#if (defined(EFR32MG24) && defined(WF200_WIFI)) + if (pr_type != LCD) + { + pr_type = LCD; + } +#endif /* Initialize the DMD module for the DISPLAY device driver. */ status = DMD_init(0); if (DMD_OK != status) @@ -117,7 +126,18 @@ int SilabsLCD::DrawPixel(void * pContext, int32_t x, int32_t y) int SilabsLCD::Update(void) { - return DMD_updateDisplay(); + int status; +#if (defined(EFR32MG24) && defined(WF200_WIFI)) + pre_lcd_spi_transfer(); +#endif + status = DMD_updateDisplay(); +#if (defined(EFR32MG24) && defined(WF200_WIFI)) + post_lcd_spi_transfer(); +#endif + /* + * TO-DO; Above logic can be optimised by writing a common API + */ + return status; } void SilabsLCD::WriteDemoUI(bool state) @@ -180,8 +200,14 @@ void SilabsLCD::WriteQRCode() } } } +#if (defined(EFR32MG24) && defined(WF200_WIFI)) + pre_lcd_spi_transfer(); +#endif DMD_updateDisplay(); +#if (defined(EFR32MG24) && defined(WF200_WIFI)) + post_lcd_spi_transfer(); +#endif } void SilabsLCD::SetQRCode(uint8_t * str, uint32_t size) diff --git a/examples/platform/silabs/efr32/spi_multiplex.c b/examples/platform/silabs/efr32/spi_multiplex.c new file mode 100644 index 00000000000000..30e29f62d76b2c --- /dev/null +++ b/examples/platform/silabs/efr32/spi_multiplex.c @@ -0,0 +1,165 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "spi_multiplex.h" +#include "dmadrv.h" +#include "em_bus.h" +#include "em_cmu.h" +#include "em_gpio.h" +#include "em_ldma.h" +#include "em_usart.h" + +/**************************************************************************** + * @fn void spi_drv_reinit() + * @brief + * Re-Intializes SPI driver to required baudrate + * @param[in] None + * @return returns void + *****************************************************************************/ +void spi_drv_reinit(uint32_t baudrate) +{ + // USART is used in MG24 + WF200 combination + USART_InitSync_TypeDef usartInit = USART_INITSYNC_DEFAULT; + usartInit.msbf = true; + usartInit.clockMode = usartClockMode0; + usartInit.baudrate = baudrate; + uint32_t databits = SL_SPIDRV_EXP_FRAME_LENGTH - 4U + _USART_FRAME_DATABITS_FOUR; + usartInit.databits = (USART_Databits_TypeDef) databits; + usartInit.autoCsEnable = true; + + USART_InitSync(USART0, &usartInit); +} + +/**************************************************************************** + * @fn void set_spi_baudrate() + * @brief + * Setting the appropriate SPI baudrate + * @param[in] None + * @return returns void + *****************************************************************************/ +void set_spi_baudrate(peripheraltype_t pr_type) +{ + if (pr_type == LCD) + { + spi_drv_reinit(LCD_BIT_RATE); + } + else if (pr_type == EXP_HDR) + { + spi_drv_reinit(EXP_HDR_BIT_RATE); + } + else if (pr_type == EXT_SPIFLASH) + { + spi_drv_reinit(SPI_FLASH_BIT_RATE); + } +} + +/**************************************************************************** + * @fn void spiflash_cs_assert() + * @brief + * Assert SPI flash chip select. + * @param[in] None + * @return returns void + *****************************************************************************/ +void spiflash_cs_assert(void) +{ + GPIO_PinOutClear(SL_MX25_FLASH_SHUTDOWN_CS_PORT, SL_MX25_FLASH_SHUTDOWN_CS_PIN); +} + +/**************************************************************************** + * @fn void spiflash_cs_deassert() + * @brief + * De-Assert SPI flash chip select. + * @param[in] None + * @return returns void + *****************************************************************************/ +void spiflash_cs_deassert(void) +{ + GPIO_PinOutSet(SL_MX25_FLASH_SHUTDOWN_CS_PORT, SL_MX25_FLASH_SHUTDOWN_CS_PIN); +} + +/**************************************************************************** + * @fn void pre_bootloader_spi_transfer() + * @brief + * Take a semaphore and controlling CS pin for EXP header and SPI flash + * @param[in] None + * @return returns void + *****************************************************************************/ +void pre_bootloader_spi_transfer(void) +{ + if (xSemaphoreTake(spi_sem_sync_hdl, portMAX_DELAY) != pdTRUE) + { + return; + } + /* + * CS for Expansion header controlled within GSDK, + * however we need to ensure CS for Expansion header is High/disabled before use of EXT SPI Flash + */ + sl_wfx_host_spi_cs_deassert(); + /* + * Assert CS pin for EXT SPI Flash + */ + spiflash_cs_assert(); +} + +/**************************************************************************** + * @fn void post_bootloader_spi_transfer() + * @brief + * De-Assert EXT SPI flash CS pin and release semaphore + * @param[in] None + * @return returns void + *****************************************************************************/ +void post_bootloader_spi_transfer(void) +{ + /* + * De-Assert CS pin for EXT SPI Flash + */ + spiflash_cs_deassert(); + xSemaphoreGive(spi_sem_sync_hdl); +} + +/**************************************************************************** + * @fn void pre_lcd_spi_transfer() + * @brief + * Take a semaphore and setting LCD baudrate + * @param[in] None + * @return returns void + *****************************************************************************/ +void pre_lcd_spi_transfer(void) +{ + if (xSemaphoreTake(spi_sem_sync_hdl, portMAX_DELAY) != pdTRUE) + { + return; + } + if (pr_type != LCD) + { + pr_type = LCD; + set_spi_baudrate(pr_type); + } + /*LCD CS is handled as part of LCD gsdk*/ +} + +/**************************************************************************** + * @fn void post_lcd_spi_transfer() + * @brief + * Release semaphore + * @param[in] None + * @return returns void + *****************************************************************************/ +void post_lcd_spi_transfer(void) +{ + xSemaphoreGive(spi_sem_sync_hdl); +} diff --git a/examples/platform/silabs/efr32/spi_multiplex.h b/examples/platform/silabs/efr32/spi_multiplex.h new file mode 100644 index 00000000000000..21f337abbcfc99 --- /dev/null +++ b/examples/platform/silabs/efr32/spi_multiplex.h @@ -0,0 +1,57 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif +#include "FreeRTOS.h" +#include "semphr.h" +#include "sl_mx25_flash_shutdown_usart_config.h" +#include "sl_spidrv_exp_config.h" +#include "sl_wfx_host_api.h" + +#define LCD_BIT_RATE 1100000 +#define EXP_HDR_BIT_RATE 16000000 +#define SPI_FLASH_BIT_RATE 16000000 + +typedef enum PERIPHERAL_TYPE +{ + EXP_HDR = 0, + LCD, + EXT_SPIFLASH, +} peripheraltype_t; + +extern SemaphoreHandle_t spi_sem_sync_hdl; +extern peripheraltype_t pr_type; + +void spi_drv_reinit(uint32_t); +void set_spi_baudrate(peripheraltype_t); + +void spiflash_cs_assert(void); +void spiflash_cs_deassert(void); + +void pre_bootloader_spi_transfer(void); +void post_bootloader_spi_transfer(void); + +void pre_lcd_spi_transfer(void); +void post_lcd_spi_transfer(void); + +#ifdef __cplusplus +} +#endif diff --git a/examples/platform/silabs/efr32/wf200/efr_spi.c b/examples/platform/silabs/efr32/wf200/efr_spi.c index fb35093797679d..f2a5403cded85a 100644 --- a/examples/platform/silabs/efr32/wf200/efr_spi.c +++ b/examples/platform/silabs/efr32/wf200/efr_spi.c @@ -48,6 +48,12 @@ #include "sl_wfx_task.h" #include "wfx_host_events.h" +#if defined(EFR32MG24) +#include "spi_multiplex.h" +StaticSemaphore_t spi_sem_peripharal; +SemaphoreHandle_t spi_sem_sync_hdl; +peripheraltype_t pr_type = EXP_HDR; +#endif extern SPIDRV_Handle_t sl_spidrv_exp_handle; #define USART SL_WFX_HOST_PINOUT_SPI_PERIPHERAL @@ -91,9 +97,9 @@ sl_status_t sl_wfx_host_init_bus(void) * not controlled by EUSART so there is no write to the corresponding * EUSARTROUTE register to do this. */ - MY_USART->CTRL |= (1u << _USART_CTRL_SMSDELAY_SHIFT); #if defined(EFR32MG12) + MY_USART->CTRL |= (1u << _USART_CTRL_SMSDELAY_SHIFT); MY_USART->ROUTEPEN = USART_ROUTEPEN_TXPEN | USART_ROUTEPEN_RXPEN | USART_ROUTEPEN_CLKPEN; #endif @@ -106,6 +112,10 @@ sl_status_t sl_wfx_host_init_bus(void) spi_sem = xSemaphoreCreateBinaryStatic(&xEfrSpiSemaBuffer); xSemaphoreGive(spi_sem); +#if defined(EFR32MG24) + spi_sem_sync_hdl = xSemaphoreCreateBinaryStatic(&spi_sem_peripharal); + xSemaphoreGive(spi_sem_sync_hdl); +#endif return SL_STATUS_OK; } @@ -236,6 +246,18 @@ sl_status_t sl_wfx_host_spi_transfer_no_cs_assert(sl_wfx_host_bus_transfer_type_ uint8_t * buffer, uint16_t buffer_length) { sl_status_t result = SL_STATUS_FAIL; +#if defined(EFR32MG24) + if (pr_type != EXP_HDR) + { + pr_type = EXP_HDR; + set_spi_baudrate(pr_type); + } + if (xSemaphoreTake(spi_sem_sync_hdl, portMAX_DELAY) != pdTRUE) + { + return SL_STATUS_TIMEOUT; + } + sl_wfx_host_spi_cs_assert(); +#endif const bool is_read = (type == SL_WFX_BUS_READ); while (!(MY_USART->STATUS & USART_STATUS_TXBL)) @@ -286,7 +308,10 @@ sl_status_t sl_wfx_host_spi_transfer_no_cs_assert(sl_wfx_host_bus_transfer_type_ result = SL_STATUS_TIMEOUT; } } - +#if defined(EFR32MG24) + sl_wfx_host_spi_cs_deassert(); + xSemaphoreGive(spi_sem_sync_hdl); +#endif return result; } @@ -403,6 +428,10 @@ void sl_wfx_host_gpio_init(void) // Enable GPIO clock. CMU_ClockEnable(cmuClock_GPIO, true); +#if defined(EFR32MG24) + // configure WF200 CS pin. + GPIO_PinModeSet(SL_SPIDRV_EXP_CS_PORT, SL_SPIDRV_EXP_CS_PIN, gpioModePushPull, 1); +#endif // Configure WF200 reset pin. GPIO_PinModeSet(SL_WFX_HOST_PINOUT_RESET_PORT, SL_WFX_HOST_PINOUT_RESET_PIN, gpioModePushPull, 0); // Configure WF200 WUP pin. diff --git a/examples/platform/silabs/efr32/wf200/wf200.gni b/examples/platform/silabs/efr32/wf200/wf200.gni index 358384a81121bf..fbe67d002faf67 100644 --- a/examples/platform/silabs/efr32/wf200/wf200.gni +++ b/examples/platform/silabs/efr32/wf200/wf200.gni @@ -27,4 +27,5 @@ wf200_plat_src = [ "${examples_plat_dir}/wf200/wf200_init.c", "${examples_plat_dir}/wf200/efr_spi.c", "${examples_plat_dir}/wf200/host_if.cpp", + "${examples_plat_dir}/spi_multiplex.c", ] diff --git a/src/platform/silabs/EFR32/OTAImageProcessorImpl.cpp b/src/platform/silabs/EFR32/OTAImageProcessorImpl.cpp index f07fd947d03c17..82150a28c397a7 100644 --- a/src/platform/silabs/EFR32/OTAImageProcessorImpl.cpp +++ b/src/platform/silabs/EFR32/OTAImageProcessorImpl.cpp @@ -23,6 +23,10 @@ extern "C" { #include "btl_interface.h" #include "em_bus.h" // For CORE_CRITICAL_SECTION +#if (defined(EFR32MG24) && defined(WF200_WIFI)) +#include "sl_wfx_host_api.h" +#include "spi_multiplex.h" +#endif } #include @@ -162,8 +166,13 @@ void OTAImageProcessorImpl::HandleFinalize(intptr_t context) writeBuffer[writeBufOffset] = 0; writeBufOffset++; } - +#if (defined(EFR32MG24) && defined(WF200_WIFI)) + pre_bootloader_spi_transfer(); +#endif CORE_CRITICAL_SECTION(err = bootloader_eraseWriteStorage(mSlotId, mWriteOffset, writeBuffer, kAlignmentBytes);) +#if (defined(EFR32MG24) && defined(WF200_WIFI)) + post_bootloader_spi_transfer(); +#endif if (err) { ChipLogError(SoftwareUpdate, "ERROR: In HandleFinalize bootloader_eraseWriteStorage() error %ld", err); @@ -185,7 +194,9 @@ void OTAImageProcessorImpl::HandleApply(intptr_t context) // Force KVS to store pending keys such as data from StoreCurrentUpdateInfo() chip::DeviceLayer::PersistedStorage::KeyValueStoreMgrImpl().ForceKeyMapSave(); - +#if (defined(EFR32MG24) && defined(WF200_WIFI)) + pre_bootloader_spi_transfer(); +#endif CORE_CRITICAL_SECTION(err = bootloader_verifyImage(mSlotId, NULL);) if (err != SL_BOOTLOADER_OK) { @@ -204,6 +215,9 @@ void OTAImageProcessorImpl::HandleApply(intptr_t context) // This reboots the device CORE_CRITICAL_SECTION(bootloader_rebootAndInstall();) +#if (defined(EFR32MG24) && defined(WF200_WIFI)) + xSemaphoreGive(spi_sem_sync_hdl); +#endif } void OTAImageProcessorImpl::HandleAbort(intptr_t context) @@ -254,8 +268,13 @@ void OTAImageProcessorImpl::HandleProcessBlock(intptr_t context) if (writeBufOffset == kAlignmentBytes) { writeBufOffset = 0; - +#if (defined(EFR32MG24) && defined(WF200_WIFI)) + pre_bootloader_spi_transfer(); +#endif CORE_CRITICAL_SECTION(err = bootloader_eraseWriteStorage(mSlotId, mWriteOffset, writeBuffer, kAlignmentBytes);) +#if (defined(EFR32MG24) && defined(WF200_WIFI)) + post_bootloader_spi_transfer(); +#endif if (err) { ChipLogError(SoftwareUpdate, "ERROR: In HandleProcessBlock bootloader_eraseWriteStorage() error %ld", err);