From a69d66b08ecb710932a2cd05acbc787dc0eebb58 Mon Sep 17 00:00:00 2001 From: IOsetting Date: Sat, 1 Apr 2023 00:41:17 +0800 Subject: [PATCH] feat: i2c pin multiplexing example for py32f003w --- .../bsp_i2c.c | 0 .../bsp_i2c.h | 0 .../main.c | 6 +- .../main.h | 0 .../pcf8574_lcd.c | 0 .../pcf8574_lcd.h | 0 .../py32f0xx_it.c | 0 .../py32f0xx_it.h | 0 .../bsp_i2c.c | 227 +++++++++++++++++ .../bsp_i2c.h | 35 +++ .../PCF8574_1602LCD_PY32F003W_PF0_PF1/main.c | 235 ++++++++++++++++++ .../PCF8574_1602LCD_PY32F003W_PF0_PF1/main.h | 44 ++++ .../pcf8574_lcd.c | 110 ++++++++ .../pcf8574_lcd.h | 127 ++++++++++ .../py32f0xx_it.c | 40 +++ .../py32f0xx_it.h | 19 ++ 16 files changed, 842 insertions(+), 1 deletion(-) rename Examples/LL/I2C/{PCF8574_1602LCD_PY32F003W => PCF8574_1602LCD_PY32F003W_PA2_PA3}/bsp_i2c.c (100%) rename Examples/LL/I2C/{PCF8574_1602LCD_PY32F003W => PCF8574_1602LCD_PY32F003W_PA2_PA3}/bsp_i2c.h (100%) rename Examples/LL/I2C/{PCF8574_1602LCD_PY32F003W => PCF8574_1602LCD_PY32F003W_PA2_PA3}/main.c (97%) rename Examples/LL/I2C/{PCF8574_1602LCD_PY32F003W => PCF8574_1602LCD_PY32F003W_PA2_PA3}/main.h (100%) rename Examples/LL/I2C/{PCF8574_1602LCD_PY32F003W => PCF8574_1602LCD_PY32F003W_PA2_PA3}/pcf8574_lcd.c (100%) rename Examples/LL/I2C/{PCF8574_1602LCD_PY32F003W => PCF8574_1602LCD_PY32F003W_PA2_PA3}/pcf8574_lcd.h (100%) rename Examples/LL/I2C/{PCF8574_1602LCD_PY32F003W => PCF8574_1602LCD_PY32F003W_PA2_PA3}/py32f0xx_it.c (100%) rename Examples/LL/I2C/{PCF8574_1602LCD_PY32F003W => PCF8574_1602LCD_PY32F003W_PA2_PA3}/py32f0xx_it.h (100%) create mode 100644 Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PF0_PF1/bsp_i2c.c create mode 100644 Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PF0_PF1/bsp_i2c.h create mode 100644 Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PF0_PF1/main.c create mode 100644 Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PF0_PF1/main.h create mode 100755 Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PF0_PF1/pcf8574_lcd.c create mode 100755 Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PF0_PF1/pcf8574_lcd.h create mode 100644 Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PF0_PF1/py32f0xx_it.c create mode 100644 Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PF0_PF1/py32f0xx_it.h diff --git a/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W/bsp_i2c.c b/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PA2_PA3/bsp_i2c.c similarity index 100% rename from Examples/LL/I2C/PCF8574_1602LCD_PY32F003W/bsp_i2c.c rename to Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PA2_PA3/bsp_i2c.c diff --git a/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W/bsp_i2c.h b/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PA2_PA3/bsp_i2c.h similarity index 100% rename from Examples/LL/I2C/PCF8574_1602LCD_PY32F003W/bsp_i2c.h rename to Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PA2_PA3/bsp_i2c.h diff --git a/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W/main.c b/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PA2_PA3/main.c similarity index 97% rename from Examples/LL/I2C/PCF8574_1602LCD_PY32F003W/main.c rename to Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PA2_PA3/main.c index 13c9ed6..6dbedd2 100644 --- a/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W/main.c +++ b/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PA2_PA3/main.c @@ -13,12 +13,16 @@ // limitations under the License. /*** - * Demo: I2C - PCF8574 1602 LCD + * Demo: PY32F003Wx(SOP16) I2C - PCF8574 1602 LCD * * PY32F003W(SOP16) PCF8574 1602 LCD * PA3 SCL * PA2 SDA + * + * Note: + * This demo is specific for PY32F003Wx of SOP16 packaging */ + #include #include "main.h" #include "py32f0xx_bsp_printf.h" diff --git a/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W/main.h b/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PA2_PA3/main.h similarity index 100% rename from Examples/LL/I2C/PCF8574_1602LCD_PY32F003W/main.h rename to Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PA2_PA3/main.h diff --git a/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W/pcf8574_lcd.c b/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PA2_PA3/pcf8574_lcd.c similarity index 100% rename from Examples/LL/I2C/PCF8574_1602LCD_PY32F003W/pcf8574_lcd.c rename to Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PA2_PA3/pcf8574_lcd.c diff --git a/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W/pcf8574_lcd.h b/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PA2_PA3/pcf8574_lcd.h similarity index 100% rename from Examples/LL/I2C/PCF8574_1602LCD_PY32F003W/pcf8574_lcd.h rename to Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PA2_PA3/pcf8574_lcd.h diff --git a/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W/py32f0xx_it.c b/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PA2_PA3/py32f0xx_it.c similarity index 100% rename from Examples/LL/I2C/PCF8574_1602LCD_PY32F003W/py32f0xx_it.c rename to Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PA2_PA3/py32f0xx_it.c diff --git a/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W/py32f0xx_it.h b/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PA2_PA3/py32f0xx_it.h similarity index 100% rename from Examples/LL/I2C/PCF8574_1602LCD_PY32F003W/py32f0xx_it.h rename to Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PA2_PA3/py32f0xx_it.h diff --git a/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PF0_PF1/bsp_i2c.c b/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PF0_PF1/bsp_i2c.c new file mode 100644 index 0000000..ff19de3 --- /dev/null +++ b/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PF0_PF1/bsp_i2c.c @@ -0,0 +1,227 @@ +#include +#include "bsp_i2c.h" + + +#define I2C_SELF_ADDRESS 0xA0 /* host address */ +#define I2C_MAX_TIMEOUT 0x2000 +#define I2C_STATE_READY 0 +#define I2C_STATE_BUSY_TX 1 +#define I2C_STATE_BUSY_RX 2 + +__IO uint32_t i2cState = I2C_STATE_READY; + + +void BSP_I2C_Config(void) +{ + LL_I2C_InitTypeDef I2C_InitStruct; + + LL_I2C_DeInit(I2C1); + /* + * Clock speed: + * - standard = 100khz, if PLL is on, set system clock <= 16MHz, or I2C might not work + * - fast = 400khz + */ + I2C_InitStruct.ClockSpeed = LL_I2C_MAX_SPEED_FAST; + I2C_InitStruct.DutyCycle = LL_I2C_DUTYCYCLE_16_9; + I2C_InitStruct.OwnAddress1 = I2C_SELF_ADDRESS; + I2C_InitStruct.TypeAcknowledge = LL_I2C_NACK; + LL_I2C_Init(I2C1, &I2C_InitStruct); + + /* Enale clock stretch (reset default: on) */ + // LL_I2C_EnableClockStretching(I2C1); + + /* Enable general call (reset default: off) */ + // LL_I2C_EnableGeneralCall(I2C1); +} + + +void BSP_I2C_Scan(void) +{ + for(uint16_t i = 0; i < 128; i++) + { + if(BSP_I2C_IsDeviceReady(i << 1, I2C_MAX_TIMEOUT) == SUCCESS) + { + printf("Found address: 0x%02X\r\n", i << 1); + } + } +} + +ErrorStatus BSP_I2C_IsDeviceReady(uint8_t devAddress, uint16_t timeout) +{ + uint16_t t = timeout; + while (i2cState == I2C_STATE_BUSY_TX && t--); + if (t == 0) return ERROR; + t = timeout; + + LL_I2C_DisableBitPOS(I2C1); + + i2cState = I2C_STATE_BUSY_TX; + + /* Start */ + LL_I2C_GenerateStartCondition(I2C1); + while (LL_I2C_IsActiveFlag_SB(I2C1) != 1 && t--); + if (t == 0) + { + i2cState = I2C_STATE_READY; + return ERROR; + } + t = timeout; + + /* Send slave address */ + LL_I2C_TransmitData8(I2C1, (devAddress & (uint8_t)(~0x01))); + while (LL_I2C_IsActiveFlag_ADDR(I2C1) != 1 && t--) + if (t == 0) + { + i2cState = I2C_STATE_READY; + return ERROR; + } + t = timeout; + + LL_I2C_ClearFlag_ADDR(I2C1); + + /* Stop */ + LL_I2C_GenerateStopCondition(I2C1); + + i2cState = I2C_STATE_READY; + return SUCCESS; +} + +ErrorStatus BSP_I2C_MasterTransmit(uint16_t devAddress, uint8_t *pData, uint16_t len, uint16_t timeout) +{ + uint16_t t = timeout; + + while (i2cState == I2C_STATE_BUSY_TX && t--) + if (t == 0) return ERROR; + t = timeout; + + LL_I2C_DisableBitPOS(I2C1); + i2cState = I2C_STATE_BUSY_TX; + + /* Start */ + LL_I2C_GenerateStartCondition(I2C1); + while (LL_I2C_IsActiveFlag_SB(I2C1) != 1 && t--) + if (t == 0) + { + i2cState = I2C_STATE_READY; + return ERROR; + } + t = timeout; + + /* Send slave address */ + LL_I2C_TransmitData8(I2C1, (devAddress & (uint8_t)(~0x01))); + while (LL_I2C_IsActiveFlag_ADDR(I2C1) != 1 && t--) + if (t == 0) + { + i2cState = I2C_STATE_READY; + return ERROR; + } + t = timeout; + + LL_I2C_ClearFlag_ADDR(I2C1); + + /* Transfer data */ + while (len > 0) + { + while (LL_I2C_IsActiveFlag_TXE(I2C1) != 1 && t--) + if (t == 0) + { + i2cState = I2C_STATE_READY; + return ERROR; + } + t = timeout; + + LL_I2C_TransmitData8(I2C1, *pData++); + len--; + + while (LL_I2C_IsActiveFlag_BTF(I2C1) != 1 && t--) + if (t == 0) + { + i2cState = I2C_STATE_READY; + return ERROR; + } + t = timeout; + } + + /* Stop */ + LL_I2C_GenerateStopCondition(I2C1); + + i2cState = I2C_STATE_READY; + return SUCCESS; +} + +ErrorStatus BSP_I2C_Transmit(uint8_t devAddress, uint8_t memAddress, uint8_t *pData, uint16_t len, uint16_t timeout) +{ + uint16_t t = timeout; + + while (i2cState == I2C_STATE_BUSY_TX && t--) + if (t == 0) return ERROR; + t = timeout; + + LL_I2C_DisableBitPOS(I2C1); + + i2cState = I2C_STATE_BUSY_TX; + + /* Start */ + LL_I2C_GenerateStartCondition(I2C1); + while (LL_I2C_IsActiveFlag_SB(I2C1) != 1 && t--) + if (t == 0) + { + i2cState = I2C_STATE_READY; + return ERROR; + } + t = timeout; + /* Send slave address */ + LL_I2C_TransmitData8(I2C1, (devAddress & (uint8_t)(~0x01))); + while (LL_I2C_IsActiveFlag_ADDR(I2C1) != 1 && t--) + if (t == 0) + { + i2cState = I2C_STATE_READY; + return ERROR; + } + t = timeout; + LL_I2C_ClearFlag_ADDR(I2C1); + + /* Send memory address */ + LL_I2C_TransmitData8(I2C1, memAddress); + while (LL_I2C_IsActiveFlag_BTF(I2C1) != 1 && t--) + if (t == 0) + { + i2cState = I2C_STATE_READY; + return ERROR; + } + t = timeout; + + /* Transfer data */ + while (len > 0) + { + while (LL_I2C_IsActiveFlag_TXE(I2C1) != 1 && t--) + if (t == 0) + { + i2cState = I2C_STATE_READY; + return ERROR; + } + t = timeout; + + LL_I2C_TransmitData8(I2C1, *pData++); + len--; + + if ((LL_I2C_IsActiveFlag_BTF(I2C1) == 1) && (len != 0U)) + { + LL_I2C_TransmitData8(I2C1, *pData++); + len--; + } + + while (LL_I2C_IsActiveFlag_BTF(I2C1) != 1 && t--) + if (t == 0) + { + i2cState = I2C_STATE_READY; + return ERROR; + } + t = timeout; + } + + /* Stop */ + LL_I2C_GenerateStopCondition(I2C1); + i2cState = I2C_STATE_READY; + return SUCCESS; +} diff --git a/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PF0_PF1/bsp_i2c.h b/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PF0_PF1/bsp_i2c.h new file mode 100644 index 0000000..cf8f20e --- /dev/null +++ b/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PF0_PF1/bsp_i2c.h @@ -0,0 +1,35 @@ +// Copyright 2021 IOsetting +// +// 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. + +#ifndef __BSP_I2C_H +#define __BSP_I2C_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "py32f0xx_ll_i2c.h" +#include "py32f0xx_ll_utils.h" + +void BSP_I2C_Config(void); +void BSP_I2C_Scan(void); +ErrorStatus BSP_I2C_IsDeviceReady(uint8_t devAddress, uint16_t timeout); +ErrorStatus BSP_I2C_MasterTransmit(uint16_t devAddress, uint8_t *pData, uint16_t len, uint16_t timeout); +ErrorStatus BSP_I2C_Transmit(uint8_t devAddress, uint8_t memAddress, uint8_t *pData, uint16_t len, uint16_t timeout); + +#ifdef __cplusplus +} +#endif + +#endif /* __BSP_I2C_H */ diff --git a/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PF0_PF1/main.c b/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PF0_PF1/main.c new file mode 100644 index 0000000..7a4e2d6 --- /dev/null +++ b/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PF0_PF1/main.c @@ -0,0 +1,235 @@ +// Copyright 2021 IOsetting +// +// 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. + +/*** + * Demo: PY32F003Wx(SOP16) I2C - PCF8574 1602 LCD + * + * PY32F003W PCF8574 1602 LCD + * PF1 SCL + * PF0 SDA + * + * Note: + * 1. This demo is specific for PY32F003Wx of SOP16 packaging + * If PF0/PF2 is connected to a reset button, make sure there is no + * capacitor connected to it, otherwise it will ruin the SDA signal. + * And make sure no extra resistors and capacitors connected to PF1/PA14. + * + * 2. After running this demo, RESET button will stop working, run demo + * "RestoreOptionBytes" to restore the RESET function on PF0/PF2. + */ +#include +#include "main.h" +#include "py32f0xx_bsp_printf.h" +#include "py32f0xx_bsp_clock.h" +#include "pcf8574_lcd.h" + +const uint8_t cgrom[] = { + 0x1f, 0x1f, 0x1f, 0x1f, 0x00, 0x00, 0x00, 0x00, /* "" 0 */ + 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x1f, /* ,, 1 */ + 0x01, 0x07, 0x0f, 0x0f, 0x1f, 0x1f, 0x1f, 0x1f, /* /| 2 */ + 0x10, 0x1c, 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, /* |\ 3 */ + 0x1f, 0x1f, 0x1f, 0x1f, 0x0f, 0x0f, 0x07, 0x01, /* \| 4 */ + 0x1f, 0x1f, 0x1f, 0x1f, 0x1e, 0x1e, 0x1c, 0x10, /* |/ 5 */ + 0x00, 0x00, 0x00, 0x00, 0x10, 0x1c, 0x1e, 0x1e, /* |\ 6 */ + 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x00 /* . 7 */ +}; + +static void APP_GPIO_Config(void); +static void APP_FlashSetOptionBytes(void); + +int main(void) +{ + uint8_t i; + + BSP_RCC_HSI_24MConfig(); + /** + * Important: + * delay 2 seconds before SWD port stop working, so you will have + * enougth time to re-flash the MCU + */ + LL_mDelay(2000); + + /* Check if PF0/PF2 pin has been set as GPIO pin*/ + if(READ_BIT(FLASH->OPTR, FLASH_OPTR_NRST_MODE) == OB_RESET_MODE_RESET) + { + /* If not, turn off the RESET function on pin(PF0/PF2), this will reset the MCU */ + APP_FlashSetOptionBytes(); + } + else + { + BSP_USART_Config(115200); + printf("I2C Demo: PCF8574 1602 LCD\r\nClock: %ld\r\n", SystemCoreClock); + printf("RESET has been configurated as GPIO\r\n"); + } + + APP_GPIO_Config(); + BSP_I2C_Config(); + + printf("Scanning I2C bus...\r\n"); + BSP_I2C_Scan(); + + LCD_Init(LCD1602_I2C_ADDR); + + for(;;) + { + // clear display + LCD_SendCommand(LCD1602_I2C_ADDR, LCD1602_CMD_CLEAR_DISPLAY); + LL_mDelay(500); + // move cursor to 0,0 + LCD_SendCommand(LCD1602_I2C_ADDR, LCD1602_DDRAM_ROW0|0); + LCD_SendString(LCD1602_I2C_ADDR, " Using 1602 LCD"); + // move cursor to 1,0 + LCD_SendCommand(LCD1602_I2C_ADDR, LCD1602_DDRAM_ROW1|0); + LCD_SendString(LCD1602_I2C_ADDR, " over I2C bus"); + LL_mDelay(1500); + + // CGRAM test + for (i = 0; i < 8; i++) + { + LCD_SetCGRAM(LCD1602_I2C_ADDR, i, &cgrom[i * 8]); + } + LCD_SendCommand(LCD1602_I2C_ADDR, LCD1602_CMD_CLEAR_DISPLAY); + LL_mDelay(500); + // move cursor to 0,0 + LCD_SendCommand(LCD1602_I2C_ADDR, LCD1602_DDRAM_ROW0|0); + LCD_SendString(LCD1602_I2C_ADDR, "Custom chars"); + LL_mDelay(500); + LCD_SendCommand(LCD1602_I2C_ADDR, LCD1602_DDRAM_ROW1|0); + for (i = 0; i < 8; i++) + { + LCD_SendData(LCD1602_I2C_ADDR, i); + LL_mDelay(200); + } + LCD_SendString(LCD1602_I2C_ADDR, " done"); + LL_mDelay(1500); + + // Shift display test + LCD_SendCommand(LCD1602_I2C_ADDR, LCD1602_CMD_CLEAR_DISPLAY); + LL_mDelay(500); + LCD_SendCommand(LCD1602_I2C_ADDR, LCD1602_DDRAM_ROW0|9); + LCD_SendString(LCD1602_I2C_ADDR, "Shift"); + LCD_SendCommand(LCD1602_I2C_ADDR, LCD1602_DDRAM_ROW1|8); + LCD_SendString(LCD1602_I2C_ADDR, "<<<->>>"); + LL_mDelay(500); + for (i = 0; i < 8; i++) + { + LCD_SendCommand(LCD1602_I2C_ADDR, LCD1602_CMD_DISPLAY_SHIFT_LEFT); + LL_mDelay(200); + } + LL_mDelay(500); + for (i = 0; i < 8; i++) + { + LCD_SendCommand(LCD1602_I2C_ADDR, LCD1602_CMD_DISPLAY_SHIFT_RIGHT); + LL_mDelay(200); + } + LL_mDelay(1500); + + // Move cursor test + LCD_SendCommand(LCD1602_I2C_ADDR, LCD1602_CMD_CLEAR_DISPLAY); + LL_mDelay(500); + LCD_SendCommand(LCD1602_I2C_ADDR, LCD1602_DDRAM_ROW0|0); + LCD_SendString(LCD1602_I2C_ADDR, "Move cursor"); + LL_mDelay(500); + for (i = 0; i < 11; i++) + { + LCD_SendCommand(LCD1602_I2C_ADDR, LCD1602_CMD_CURSOR_MOVE_LEFT); + LL_mDelay(200); + } + LL_mDelay(500); + for (i = 0; i < 12; i++) + { + LCD_SendCommand(LCD1602_I2C_ADDR, LCD1602_CMD_CURSOR_MOVE_RIGHT); + LL_mDelay(200); + } + LL_mDelay(500); + LCD_SendCommand(LCD1602_I2C_ADDR, LCD1602_DDRAM_ROW1|11); + LCD_SendString(LCD1602_I2C_ADDR, "done"); + + LL_mDelay(2000); + } +} + +static void APP_GPIO_Config(void) +{ + LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; + + LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOF); + LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1); + + /** + * SCL: PF1 & AF_12 + * SDA: PF0 & AF_12 + */ + // PF1 SCL + GPIO_InitStruct.Pin = LL_GPIO_PIN_1; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; + GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH; + GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN; + GPIO_InitStruct.Pull = LL_GPIO_PULL_UP; + GPIO_InitStruct.Alternate = LL_GPIO_AF_12; + LL_GPIO_Init(GPIOF, &GPIO_InitStruct); + + // PF0 SDA + GPIO_InitStruct.Pin = LL_GPIO_PIN_0; + GPIO_InitStruct.Alternate = LL_GPIO_AF_12; + LL_GPIO_Init(GPIOF, &GPIO_InitStruct); + + /** + * According to datasheet Page-20, other pins should be set as ANALOG. + */ + // PA14 + LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_14, LL_GPIO_MODE_ANALOG); + // PF2 + LL_GPIO_SetPinMode(GPIOF, LL_GPIO_PIN_2, LL_GPIO_MODE_ANALOG); + + /* Reset I2C */ + LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C1); + LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C1); +} + +/** + * Write Option Bytes to turn off the RESET function on pin(PF0/PF2), this will reset the MCU +*/ +static void APP_FlashSetOptionBytes(void) +{ + FLASH_OBProgramInitTypeDef OBInitCfg; + + LL_FLASH_Unlock(); + LL_FLASH_OB_Unlock(); + + OBInitCfg.OptionType = OPTIONBYTE_USER; + OBInitCfg.USERType = OB_USER_BOR_EN | OB_USER_BOR_LEV | OB_USER_IWDG_SW | OB_USER_WWDG_SW | OB_USER_NRST_MODE | OB_USER_nBOOT1; + /* + * The default value: OB_BOR_DISABLE | OB_BOR_LEVEL_3p1_3p2 | OB_IWDG_SW | OB_WWDG_SW | OB_RESET_MODE_RESET | OB_BOOT1_SYSTEM; + */ + OBInitCfg.USERConfig = OB_BOR_DISABLE | OB_BOR_LEVEL_3p1_3p2 | OB_IWDG_SW | OB_WWDG_SW | OB_RESET_MODE_GPIO | OB_BOOT1_SYSTEM; + LL_FLASH_OBProgram(&OBInitCfg); + + LL_FLASH_Lock(); + LL_FLASH_OB_Lock(); + /* Reload option bytes */ + LL_FLASH_OB_Launch(); +} + +void APP_ErrorHandler(void) +{ + while (1); +} + +#ifdef USE_FULL_ASSERT +void assert_failed(uint8_t *file, uint32_t line) +{ + while (1); +} +#endif /* USE_FULL_ASSERT */ diff --git a/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PF0_PF1/main.h b/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PF0_PF1/main.h new file mode 100644 index 0000000..e5c26b3 --- /dev/null +++ b/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PF0_PF1/main.h @@ -0,0 +1,44 @@ +// Copyright 2021 IOsetting +// +// 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. + +#ifndef __MAIN_H +#define __MAIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "py32f0xx_ll_bus.h" +#include "py32f0xx_ll_cortex.h" +#include "py32f0xx_ll_dma.h" +#include "py32f0xx_ll_exti.h" +#include "py32f0xx_ll_flash.h" +#include "py32f0xx_ll_gpio.h" +#include "py32f0xx_ll_pwr.h" +#include "py32f0xx_ll_rcc.h" +#include "py32f0xx_ll_i2c.h" +#include "py32f0xx_ll_system.h" +#include "py32f0xx_ll_tim.h" +#include "py32f0xx_ll_utils.h" + +#include "bsp_i2c.h" + +void APP_ErrorHandler(void); + + +#ifdef __cplusplus +} +#endif + +#endif /* __MAIN_H */ diff --git a/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PF0_PF1/pcf8574_lcd.c b/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PF0_PF1/pcf8574_lcd.c new file mode 100755 index 0000000..4daa8c6 --- /dev/null +++ b/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PF0_PF1/pcf8574_lcd.c @@ -0,0 +1,110 @@ +// Copyright 2021 IOsetting +// +// 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 "pcf8574_lcd.h" + + +ErrorStatus LCD_SendInternal(uint8_t lcd_addr, uint8_t data, uint8_t flags) +{ + ErrorStatus status; + for(;;) + { + status = BSP_I2C_IsDeviceReady(lcd_addr, 5000); + if(status == SUCCESS) + { + break; + } + } + + uint8_t up = data & 0xF0; + uint8_t lo = (data << 4) & 0xF0; + + uint8_t data_arr[4]; + data_arr[0] = up|flags|BACKLIGHT|PIN_EN; + data_arr[1] = up|flags|BACKLIGHT; + data_arr[2] = lo|flags|BACKLIGHT|PIN_EN; + data_arr[3] = lo|flags|BACKLIGHT; + + status = BSP_I2C_MasterTransmit(lcd_addr, data_arr, sizeof(data_arr), 5000); + LL_mDelay(LCD1602_DELAY); + return status; +} + +void LCD_SendCommand(uint8_t lcd_addr, uint8_t cmd) +{ + LCD_SendInternal(lcd_addr, cmd, 0); +} + +void LCD_SendData(uint8_t lcd_addr, uint8_t data) +{ + LCD_SendInternal(lcd_addr, data, PIN_RS); +} + +void LCD_SetCGRAM(uint8_t lcd_addr, uint8_t char_addr, const uint8_t *char_font) +{ + uint8_t i = 8; + + LCD_SendCommand(lcd_addr, LCD1602_CMD_CGRAM_ADDR | (char_addr << 3)); + + while(i--) + { + LCD_SendData(lcd_addr, *char_font++ ); + } + + LCD_SendCommand(lcd_addr, LCD1602_CMD_CGRAM_ADDR); +} + +/** + * Initialize LCD + * + * Described in HD44780 datasheet P45, procedures on 4-bit initializations, + * - Wait for more than 40 ms after VCC rises to 2.7 V + * - Function set (Interface is 8 bits long), Wait for more than 4.1 ms + * - Function set (Interface is 8 bits long), Wait for more than 100 µs + * - Function set (Interface is 8 bits long) + * - Function set (Set interface to be 4 bits long.) Interface is 8 bits in length + * - Function set (Interface is 4 bits long. Specify the number of display lines and character font.) + * The number of display lines and character font cannot be changed after this point. +*/ +void LCD_Init(uint8_t lcd_addr) +{ + // need at least 40ms after power rises above 2.7V + LL_mDelay(50); + // start in 8-bit mode, 3 commands + LCD_SendCommand(lcd_addr, LCD1602_CMD_FUNC_8B_1L_5X8); + LCD_SendCommand(lcd_addr, LCD1602_CMD_FUNC_8B_1L_5X8); + LCD_SendCommand(lcd_addr, LCD1602_CMD_FUNC_8B_1L_5X8); + // set it to 4-bit mode, interface is still 8-bit + LCD_SendCommand(lcd_addr, LCD1602_CMD_FUNC_4B_1L_5X8); + + // now interface is 4-bit, set it to 2 lines and 5x8 font + LCD_SendCommand(lcd_addr, LCD1602_CMD_FUNC_4B_2L_5X8); + // display & cursor home + LCD_SendCommand(lcd_addr, LCD1602_CMD_HOME); + // display on, right shift, underline off, blink off + LCD_SendCommand(lcd_addr, LCD1602_CMD_MODE_ON_CURSOR_BLNK); + // move direction right + LCD_SendCommand(lcd_addr, LCD1602_CMD_DIRECTION_RIGHT); + // clear display (optional here) + LCD_SendCommand(lcd_addr, LCD1602_CMD_CLEAR_DISPLAY); +} + +void LCD_SendString(uint8_t lcd_addr, char *str) +{ + while (*str) + { + LCD_SendData(lcd_addr, (uint8_t)(*str)); + str++; + } +} \ No newline at end of file diff --git a/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PF0_PF1/pcf8574_lcd.h b/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PF0_PF1/pcf8574_lcd.h new file mode 100755 index 0000000..5d309f1 --- /dev/null +++ b/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PF0_PF1/pcf8574_lcd.h @@ -0,0 +1,127 @@ +// Copyright 2021 IOsetting +// +// 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. + +/*------------------------------------------------------------- +* Instruction D7 D6 D5 D4 D3 D2 D1 D0 +* ============================================== +* Display clear 0 0 0 0 0 0 0 1 +* Cursor home 0 0 0 0 0 0 1 * +* Entry Mode Set 0 0 0 0 0 1 I/D S +* Display On/Off 0 0 0 0 1 D C B +* Curs/Disp shift 0 0 0 1 S/C R/L * * +* Function Set 0 0 1 DL N F * * +* CG RAM addr set 0 1 ---------Acg--------- +* DD RAM addr set 1 -------------Add--------- +* +* Meaning: +* * - nonvalid bit +* Acg - CG RAM address (CHARACTER GENERATOR) +* Add - DD RAM address (DATA DISPLAY) +* AC - adress counter +* +* I/D - 1-increment, 0-decrement +* S - 1-display shift, 0-no display shift +* D - 1-display ON, 0-display OFF +* C - 1-cursor ON, 0-cursor OFF +* B - 1-blink ON, 0-blink OFF +* S/C - 1-display shift, 0-cursor movement +* R/L - 1-right shift, 0-left shift +* DL - 1-8 bits data transfer, 0-4 bits data transfer +* N - 1-two lines, 0-one line +* F - 1-5x10 dot matrix, 0-5x8 dot matrix +* BF - 1-internal operation in progress, 0-display ready +* +\**************************************************************/ + +#ifndef __PCF8574_LCD_H__ +#define __PCF8574_LCD_H__ + +/* C++ detection */ +#ifdef __cplusplus +extern C { +#endif + +#include +#include +#include "main.h" + + +/* I2C address + * - 7 bit slave address, left aligned, bits 7:1 are used, LSB bit is not used + * - 0x4E or 0x7E +*/ +#define LCD1602_I2C_ADDR 0x7E +/* Delay in millisecond */ +#define LCD1602_DELAY 5 +/* Register selection */ +#define PIN_RS (1 << 0) +/* Read/Write */ +#define PIN_RW (1 << 1) +/* Chip enable */ +#define PIN_EN (1 << 2) +/* Back light - might not be available on some PCF8574 modules */ +#define BACKLIGHT (1 << 3) + +/* Clear display */ +#define LCD1602_CMD_CLEAR_DISPLAY 0b00000001 +/* Move cursor home */ +#define LCD1602_CMD_HOME 0b00000010 + +// Entry Mode, Set cursor/display moving direction +#define LCD1602_CMD_DIRECTION_RIGHT 0b00000110 +#define LCD1602_CMD_DIRECTION_LEFT 0b00000100 +#define LCD1602_CMD_DIRECTION_RIGHT_SHIFT 0b00000111 +#define LCD1602_CMD_DIRECTION_LEFT_SHIFT 0b00000101 +// Display mode +#define LCD1602_CMD_MODE_OFF 0b00001000 +#define LCD1602_CMD_MODE_ON_CURSOR_OFF 0b00001100 +#define LCD1602_CMD_MODE_ON_CURSOR_ON 0b00001110 +#define LCD1602_CMD_MODE_ON_CURSOR_BLNK 0b00001111 +// Cursor/Display Shift +#define LCD1602_CMD_CURSOR_MOVE_LEFT 0b00010000 +#define LCD1602_CMD_CURSOR_MOVE_RIGHT 0b00010100 +#define LCD1602_CMD_DISPLAY_SHIFT_LEFT 0b00011000 +#define LCD1602_CMD_DISPLAY_SHIFT_RIGHT 0b00011100 + +/* Function set: 4-bit, 1 row, 5X8 matrix */ +#define LCD1602_CMD_FUNC_4B_1L_5X8 0b00100000 +/* Function set: 4-bit, 2 row, 5X8 matrix */ +#define LCD1602_CMD_FUNC_4B_2L_5X8 0b00101000 +/* Function set: 8-bit, 1 row, 5X8 matrix */ +#define LCD1602_CMD_FUNC_8B_1L_5X8 0b00110000 +/* Function set: 8-bit, 2 row, 5X8 matrix */ +#define LCD1602_CMD_FUNC_8B_2L_5X8 0b00111000 +/* Set/Read CGRAM address */ +#define LCD1602_CMD_CGRAM_ADDR 0b01000000 +/* Set/Read DDRAM address */ +#define LCD1602_CMD_DDRAM_ADDR 0b10000000 + +/* First row address */ +#define LCD1602_DDRAM_ROW0 0b10000000 +/* Second row address */ +#define LCD1602_DDRAM_ROW1 0b11000000 + + +void LCD_SendCommand(uint8_t lcd_addr, uint8_t cmd); +void LCD_SendData(uint8_t lcd_addr, uint8_t data); +void LCD_Init(uint8_t lcd_addr); +void LCD_SendString(uint8_t lcd_addr, char *str); +void LCD_SetCGRAM(uint8_t lcd_addr, uint8_t char_addr, const uint8_t *char_font); + +/* C++ detection */ +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PF0_PF1/py32f0xx_it.c b/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PF0_PF1/py32f0xx_it.c new file mode 100644 index 0000000..3a10d14 --- /dev/null +++ b/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PF0_PF1/py32f0xx_it.c @@ -0,0 +1,40 @@ +#include "main.h" +#include "py32f0xx_it.h" + +/** + * @brief This function handles Non maskable interrupt. + */ +void NMI_Handler(void) +{ +} + +/** + * @brief This function handles Hard fault interrupt. + */ +void HardFault_Handler(void) +{ + while (1) + { + } +} + +/** + * @brief This function handles System service call via SWI instruction. + */ +void SVC_Handler(void) +{ +} + +/** + * @brief This function handles Pendable request for system service. + */ +void PendSV_Handler(void) +{ +} + +/** + * @brief This function handles System tick timer. + */ +void SysTick_Handler(void) +{ +} diff --git a/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PF0_PF1/py32f0xx_it.h b/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PF0_PF1/py32f0xx_it.h new file mode 100644 index 0000000..76b3dad --- /dev/null +++ b/Examples/LL/I2C/PCF8574_1602LCD_PY32F003W_PF0_PF1/py32f0xx_it.h @@ -0,0 +1,19 @@ +#ifndef __PY32F0XX_IT_H +#define __PY32F0XX_IT_H + +#ifdef __cplusplus +extern "C" { +#endif + +void NMI_Handler(void); +void HardFault_Handler(void); +void SVC_Handler(void); +void PendSV_Handler(void); +void SysTick_Handler(void); + + +#ifdef __cplusplus +} +#endif + +#endif /* __PY32F0XX_IT_H */