Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ BUILD_DIR = Build
# PY32F003x4, PY32F003x6, PY32F003x8,
# PY32F030x6, PY32F030x8,
# PY32F072xB
MCU_TYPE = PY32F003x4
MCU_TYPE = PY32F002Ax5

##### Options #####

Expand All @@ -31,7 +31,7 @@ FLASH_PROGRM ?= pyocd

#ARM_TOOCHAIN ?= /opt/gcc-arm/gcc-arm-11.2-2022.02-x86_64-arm-none-eabi/bin
#ARM_TOOCHAIN ?= /opt/gcc-arm/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi/bin
ARM_TOOCHAIN ?= /opt/gcc-arm/arm-gnu-toolchain-13.2.Rel1-x86_64-arm-none-eabi/bin
ARM_TOOCHAIN ?= /usr/bin

# path to JLinkExe
JLINKEXE ?= /opt/SEGGER/JLink/JLinkExe
Expand Down
84 changes: 84 additions & 0 deletions User/do_not_merge_yet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
This change is not meant to be merged in at this point. See comments on top of `User/main.c`


Pasting testing master I2C code for ESP32


``` C
// ESP32 I2C Scanner
// Based on code of Nick Gammon http://www.gammon.com.au/forum/?id=10896
// ESP32 DevKit - Arduino IDE 1.8.5
// Device tested PCF8574 - Use pullup resistors 3K3 ohms !
// PCF8574 Default Freq 100 KHz

#include <Wire.h>
#include <Arduino.h>
#include <Adafruit_PCF8574.h>

Adafruit_PCF8574 pcf8574;

void Scanner ()
{
Serial.println ();
Serial.println ("I2C scanner. Scanning ...");
uint8_t count = 0;

Wire.begin();
for (uint8_t i = 8; i < 120; i++)
{
//save start time
unsigned long startTime = micros();
Wire.beginTransmission (i); // Begin I2C transmission Address (i)
if (Wire.endTransmission () == 0) // Receive 0 = success (ACK response)
{
Serial.print ("Found address: ");
Serial.print ("0x");
Serial.print (i, HEX); // PCF8574 7 bit address
Serial.print (" time: ");
Serial.println (micros() - startTime);
count++;
}
}
Serial.print ("Found ");
Serial.print (count, DEC); // numbers of devices
Serial.println (" device(s).");
}

void setup()
{
Serial.begin (115200);
Wire.begin (26, 27); // sda= GPIO_26 /scl= GPIO_27
pcf8574.begin(0x50, &Wire);
Scanner ();
pinMode(15, INPUT);
}

uint8_t loopCount = 0;
void loop()
{
unsigned long startTime = micros();
Serial.print("Loop: ");
Serial.print(loopCount);

if (digitalRead(15) == HIGH)
{
pcf8574.digitalWriteByte(loopCount);
Serial.print(" Write: ");
Serial.print(loopCount);
}
else
{
uint8_t ret = pcf8574.digitalReadByte();
Serial.print(" Read: ");
Serial.print(ret);
}

Serial.print(" Time: ");
Serial.println (micros() - startTime);
delay (1000);
loopCount++;
}



```
164 changes: 142 additions & 22 deletions User/main.c
Original file line number Diff line number Diff line change
@@ -1,44 +1,164 @@
/***
* Demo: LED Toggle
* Demo: PoC I2C slave
*
* PA0 ------> LED+
* GND ------> LED-
* This firmware serves as an Proof-of-concept PCF8574 emulation.
* Looking at jlc parts inventory, the cheapest available I2C io expander is atleast
* 2-3x more expensive (CH423S, 28c@25u), compared to cheapest PY32F002 (10c@50u)
*
* Remember, PY32 is an powerful machine, it can also serve as and I2C ADC, charlieplexing
* controller, or could even serve as I2C-controlled programmable DC-DC converter.
*
* The code is very messy for now, I2C slave operation is apparently super-hard, and not
* well documented. You can have a look, how much developers are struggling with this, by
* googling "AddrMatchCode" (which I still have no idea what is it for).
*
* The biggest breakthrtough came from a series of articles below. They're
* targeting STM32, but Puya apparently stole all of ST's HAL code, so it seems compatible.
* https://controllerstech.com/stm32-as-i2c-slave-part-1/
*
* In summary - the purpose of this code is to handle both transmit and receive operations
* without completely freezing the I2C rail. Everything else is a bonus feature from my
* perspective :D
*
* I'm going to continue working on this, I have a lot of plans for this little smart IC.
PF1 ------> I2C1_SCL
PF0 ------> I2C1_SDA
PA2 ------> USART1_TX (logging)
*/

#include "py32f0xx_hal_dma.h"
#include "py32f0xx_hal_i2c.h"
#include "py32f0xx_bsp_printf.h"

// this print will slow the I2C read operation by a lot, but ESP32 should
// handle this well.
#define DEBUG_ISR_PRINT(...) printf(__VA_ARGS__); fflush(stdout);
// #define DEBUG_ISR_PRINT(...)

static void APP_GPIO_Config(void);
I2C_HandleTypeDef I2cHandle;
void APP_ErrorHandler(void);
static void APP_I2C_Config(void);

int main(void)
#define I2C_ADDRESS 0xA0 //0x50
uint8_t aRxBuffer[2] = {0, 0};

uint8_t main_opCpltFlag = 0;
uint8_t main_receivedFlag = 0;

void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode)
{
HAL_Init();
APP_GPIO_Config();
BSP_USART_Config();
printf("PY32F0xx LED Toggle Demo\r\nSystem Clock: %ld\r\n", SystemCoreClock);
UNUSED(AddrMatchCode);// I have no idea what this does, maybe it works with some other I2C setup

while (1)
if(TransferDirection == I2C_DIRECTION_TRANSMIT){
HAL_I2C_Slave_Seq_Receive_IT(hi2c, &aRxBuffer[0], 2, I2C_FIRST_AND_LAST_FRAME);
main_receivedFlag = 1;
} else {
HAL_I2C_Slave_Seq_Transmit_IT(hi2c, &aRxBuffer[0], 2, I2C_FIRST_AND_LAST_FRAME);
}

DEBUG_ISR_PRINT("\nmaster %s \n\r",
( TransferDirection == I2C_DIRECTION_TRANSMIT )? "write" : "read");
}

void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c)
{
uint32_t errorcode = HAL_I2C_GetError(hi2c);

if (errorcode == HAL_I2C_ERROR_AF)
{
// triggered when master tries to read/write more bytes than expected.
// for now this must be triggered for each transaction, as otherwise
// the I2C periph hangs. I'll deal with this at some point.
DEBUG_ISR_PRINT("Error callback: AF\n\r");
} else if (errorcode == HAL_I2C_ERROR_BERR)
{
HAL_Delay(1000);
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_0);
printf("echo\r\n");
DEBUG_ISR_PRINT("Error callback: BERR\n\r");
}

HAL_I2C_EnableListen_IT(hi2c);
}

void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c)
{
// This callback is actually never called
// leaving some spam if someone wants to experiment
// memset( aRxBuffer, 0, RXBUFFERSIZE);
// Rxcounter++;
// HAL_I2C_Slave_Seq_Receive_IT(hi2c, &aRxBuffer[0], 1, I2C_LAST_FRAME);
// HAL_I2C_EnableListen_IT(hi2c);
DEBUG_ISR_PRINT("rx complete %d\n\r", aRxBuffer[0]);
}

static void APP_GPIO_Config(void)
void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *hi2c)
{
GPIO_InitTypeDef GPIO_InitStruct;
// TODO: for some reason, I have to try sending another byte, or the whole
// i2c periph hangs. This call will result int HAL_I2C_ERROR_AF triggered
// in HAL_I2C_ErrorCallback, which is kinda fine.

__HAL_RCC_GPIOA_CLK_ENABLE();
// PA0
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// there are 3 variants:
// 1. try send another byte - works and results in HAL_I2C_ERROR_AF
HAL_I2C_Slave_Seq_Transmit_IT(hi2c, &aRxBuffer[0], 1, I2C_LAST_FRAME);

// 2. enable listen - hangs
// HAL_I2C_EnableListen_IT(hi2c); // maybe some day

// 3. do nothing - hangs

DEBUG_ISR_PRINT("tx complete\n\r");
}

void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c)
{
DEBUG_ISR_PRINT("listen callback\n\r");
main_opCpltFlag = 1;
HAL_I2C_EnableListen_IT(hi2c);
}

int main(void)
{
HAL_Init();

BSP_USART_Config();
printf("SystemClk is:%ld\r\n", SystemCoreClock);

APP_I2C_Config();

HAL_I2C_EnableListen_IT(&I2cHandle);
printf("listen enabled\n\r");
while(1){
if(main_opCpltFlag){
if (main_receivedFlag)
{
printf("got data %02x\n\r", aRxBuffer[0]);
fflush(stdout);
main_receivedFlag = 0;
} else {
printf("transmit complete\n\r");
fflush(stdout);
}
main_opCpltFlag = 0;
}
}
}

static void APP_I2C_Config(void)
{
I2cHandle.Instance = I2C;
I2cHandle.Init.ClockSpeed = 400000; // 100KHz ~ 400KHz
I2cHandle.Init.DutyCycle = I2C_DUTYCYCLE_16_9;
I2cHandle.Init.OwnAddress1 = I2C_ADDRESS;
I2cHandle.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
I2cHandle.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&I2cHandle) != HAL_OK)
{
APP_ErrorHandler();
}
}

void APP_ErrorHandler(void)
{
printf("errord\n");
fflush(stdout);
while (1);
}

Expand Down
2 changes: 1 addition & 1 deletion User/py32f0xx_hal_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
#define HAL_DMA_MODULE_ENABLED
/* #define HAL_LPTIM_MODULE_ENABLED */
#define HAL_PWR_MODULE_ENABLED
/* #define HAL_I2C_MODULE_ENABLED */
#define HAL_I2C_MODULE_ENABLED
#define HAL_UART_MODULE_ENABLED
/* #define HAL_SPI_MODULE_ENABLED */
/* #define HAL_RTC_MODULE_ENABLED */
Expand Down
25 changes: 25 additions & 0 deletions User/py32f0xx_hal_msp.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,29 @@ void HAL_MspInit(void)
{
}

void HAL_I2C_MspInit(I2C_HandleTypeDef *hi2c)
{
GPIO_InitTypeDef GPIO_InitStruct;

__HAL_RCC_I2C_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE();

/**
PF1 ------> I2C1_SCL
PF0 ------> I2C1_SDA
*/
GPIO_InitStruct.Pin = GPIO_PIN_1 | GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_I2C;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

__HAL_RCC_I2C_FORCE_RESET();
__HAL_RCC_I2C_RELEASE_RESET();

HAL_NVIC_SetPriority(I2C1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(I2C1_IRQn);
}

/************************ (C) COPYRIGHT Puya *****END OF FILE******************/
8 changes: 7 additions & 1 deletion User/py32f0xx_it.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
/* Private function prototypes -----------------------------------------------*/
/* Private user code ---------------------------------------------------------*/
/* External variables --------------------------------------------------------*/

extern I2C_HandleTypeDef I2cHandle;
/******************************************************************************/
/* Cortex-M0+ Processor Interruption and Exception Handlers */
/******************************************************************************/
Expand Down Expand Up @@ -75,6 +75,12 @@ void SysTick_Handler(void)
HAL_IncTick();
}

void I2C1_IRQHandler(void)
{
HAL_I2C_EV_IRQHandler(&I2cHandle);
HAL_I2C_ER_IRQHandler(&I2cHandle);
}

/******************************************************************************/
/* PY32F0xx Peripheral Interrupt Handlers */
/* Add here the Interrupt Handlers for the used peripherals. */
Expand Down