mirror of
https://github.com/IcedRooibos/py32f0-template.git
synced 2025-10-28 16:32:05 -07:00
236 lines
7.0 KiB
C
236 lines
7.0 KiB
C
// Copyright 2021 IOsetting <iosetting(at)outlook.com>
|
|
//
|
|
// 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 <string.h>
|
|
#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 */
|