CH32V003 I2C remap not working - Page 1
Forum section: electronics / general

author: Sajeev
author_rank: Contributor
timestamp: February 03, 2025, 07:55:46 am
content: Dear Forum members,I tried to remap the I2C on CH32v003 chip as the default pins PC1 and PC2 were needed for SPI. The reference manual says that on setting bits 22:1 of R32_AFIO_PCFR1 register to 0:1 the I2C will be remapped to PD0 and PD1. I tried to do that , but the I2C doesnt work. I tried to hook up a logic analyser to check wheter the SDA and SCL outputs any signal, I found the SCL is pulled to grround and SDA stays high. The I2C works fine on the default pins if enabled as usual only doesnt work with remap. Has anyone done this before? Am i doing something wrong? Please find below my I2C and GPIO setup.Code:#include CH32V003_reg.S.align 4.text.global startstart:sp_init:la sp, STACK# initialize stack pointer#Enable GPIO clocks & AFIO in APB2 clock registerla x10,R32_RCC_APB2PCENR# load address of APB2PCENR register to x10 ,for enabling GPIO A,D,C peripheralslw x11,0(x10)# load contents from peripheral register R32_RCC_APB2PCENR pointed by x10li x7,((1<<2)|(1<<4)|(1<<5)|(1<<0)|(1<<11)|(1<<12)|(1<<14))# 1<<IOPA_EN,1<<IOPC_EN,1<<IOPD_EN,1<<AFIOEN,1<<SPI enable port A,C,D and AFIO functionsor x11,x11,x7# or valuessw x11,0(x10)# store modified enable values in R32_RCC_APB2PCENR#Enable I2C clock in APB1 registerla x10,R32_RCC_APB1PCENR# load address of APB1PCENR register to x10 ,for enabling I2C peripherallw x11,0(x10)# load contents from peripheral register R32_RCC_APB1PCENR pointed by x10li x7,(1<<21)# 1<<I2C1_EN, = 1<<21 for I2C functionsor x11,x11,x7# or valuessw x11,0(x10)#I2C remap from pc1,pc2 to pd0,pd1la x10,R32_AFIO_PCFR1lw x11,0(x10)li x7,((0<<22)|(1<<1))# 01 in 22 and 1 bits will remap i2c to pd0 and pd1or x11,x11,x7sw x11,0(x10)#configure GPIO D for I2cla x10,R32_GPIOD_CFGLR# load pointer x10 with address of R32_GPIOD_CFGLR , GPIO configuration registerlw x11,0(x10)# load contents from register pointed by x10li x7,~((0xf<<4)|(0xf<<0))#clear pd1,pd0. we need to setup pd1,pd0 for I2C remapand x11,x11,x7# clear pd5,pd6,pd1,pd0 mode and cnf bits for selected pin D4,D5,D6li x7,((13<<4)|(13<<0))# multiplex open drain 10MHZ on PD0 and PD1or x11,x11,x7# OR value to registersw x11,0(x10)# store in R32_GPIOD_CFGLR#############I2C0 configurationla x10,R32_RCC_APB1PRSTR# set pointer to clock control peripheral reset registerlw x11,0(x10)# load contents to x11li x7,(1<<21)# shift 1 to 21st bit positionor x11,x11,x7# OR with x11sw x11,0(x10)# set bit 21 of R32_RCC_APB1PRSTR to reset I2C peripheralnot x7,x7# invert values in x7and x11,x11,x7# and x11 to write a 0 in 21st bitsw x11,0(x10)# store 0 in 21st bit to restart i2c enginela x10,R16_I2C_CTLR2# set clock in control 2 registerlh x11,0(x10)# copy contents of R16_I2C_CTLR2 to x11li x7,0xffffffc0# clear frequency bits 0-5 with bit mask 0xffffffc0and x11,x11,x7# AND will clear bit 0-5li x7,(8<<0)# 8Mhz I2C clock .default 24Mhz HSI/3 =8Mhz APB clockor x11,x11,x7# store APB clock frequency in bit 0-5sh x11,0(x10)# store back in R16_I2C_CTLR2la x10,R16_I2C_CKCFGR# set pointer to I2C clockregisterlh x11,0(x10)# copy values to x11 from above registerli x7,0xfffff000# clear CCR bits 0-11 with bitmask 0xfffff000and x11,x11,x7# ANDing clears bit 0-11 in x11 registerli x7,(40<<0)# CCR = t(rscl)+t(wsclh)/tpclk1 = 1000+4000/125 =40 , or (8000000/2*100000)=40 , PCLK/2*100Khz =CCRor x11,x11,x7# store calculated CCR (data sheet)in x11 by ORsh x11,0(x10)# store back in peripheral registerla x10,R16_I2C_CTLR1# set pointer to I2C control register 1lh x11,0(x10)# copy contentsli x7,(1<<0)# 1<<PE = 1<<0 enable bit is bit0,1<<10 is ack enable bitor x11,x11,x7# OR enable bit to x11sh x11,0(x10)# store half word in control register 1la x10,R16_I2C_CTLR1# set pointer to I2C control register 1lh x11,0(x10)# copy contentsli x7,(1<<10)# 1<<10 is ack enable bitor x11,x11,x7# OR ACK enable bit to x11sh x11,0(x10)# store half word in control register 1

author: brucehoult
author_rank: Super Contributor
timestamp: February 03, 2025, 08:34:03 am
content: I don't know about this specific case, but the usual answer normally lies in the region of 1) "you didn't enable the clock for your new peripheral" (e.g. D port) or 2) you didn't disable using that pin for a xtal (which IIRC is PA1&PA2)

author: Sajeev
author_rank: Contributor
timestamp: February 03, 2025, 08:43:17 am
content: Dear Sir,Thanks for the reply. The only difference with the above code and a working one is the I2C pin remapping & using the GPIOD (remapped)instead of GPIOC(default). I am using the internal oscillator . I have seen the post regarding the PA1&PA2 issue in this forum where the OP was using HSE. Here the pins are totally different. If some one can try with C code it would be nice, I am ignorant in high level language.RgardsSajeev

author: Sajeev
author_rank: Contributor
timestamp: February 03, 2025, 08:49:55 am
content: Dear,I am using CH32v003F4U6 TSSOP20 chip . 20 pin version. regrets for the omission.RegardsSajeev

author: Sajeev
author_rank: Contributor
timestamp: February 03, 2025, 11:30:03 am
content: looks like ill have to bitbang I2C if remap not possibleSajeev

author: Sajeev
author_rank: Contributor
timestamp: February 03, 2025, 03:43:52 pm
content: Dear members,finally got it working. The bit 26 =1 , bit 21=0 and bit 1=1 of AFIO_PCFR1 register makes the remap of i2C happen from PC1,2 to PD0,1.reference manual says "These bits are used to configure the I/O ports forSW function and trace function. SWD (SDI) is thedebug interface to access the core. It is alwaysused as a SWD port after system reset.0xx: SWD (SDI) enabled.100: Turn off SWD (SDI), which functions as aGPIO.Others: Invalid."Thanks for the response.regardsSajeevThe working remapped code for pd0,pd1 is as belowCode:.align 4.text.global startstart:sp_init:la sp, STACK# initialize stack pointer#Enable GPIO clocks & AFIO in APB2 clock registerla x10,R32_RCC_APB2PCENR# load address of APB2PCENR register to x10 ,for enabling GPIO A,D,C peripheralslw x11,0(x10)# load contents from peripheral register R32_RCC_APB2PCENR pointed by x10li x7,((1<<2)|(1<<4)|(1<<5)|(1<<0)|(1<<11)|(1<<12)|(1<<14))# 1<<IOPA_EN,1<<IOPC_EN,1<<IOPD_EN,1<<AFIOEN,1<<SPI enable port A,C,D and AFIO functionsor x11,x11,x7# or valuessw x11,0(x10)# store modified enable values in R32_RCC_APB2PCENR#Enable I2C clock in APB1 registerla x10,R32_RCC_APB1PCENR# load address of APB1PCENR register to x10 ,for enabling I2C peripherallw x11,0(x10)# load contents from peripheral register R32_RCC_APB1PCENR pointed by x10li x7,(1<<21)# 1<<I2C1_EN, = 1<<21 for I2C functionsor x11,x11,x7# or valuessw x11,0(x10)#I2C remap from pc1,pc2 to pd0,pd1la x10,R32_AFIO_PCFR1# load address of REMAP registerlw x11,0(x10)# copy contentsli x7,((1<<26)|(0<<22)|(1<<1))# enable SWCFG(2:0)to 100 ,0:1 in 22:1 bits will remap i2c to pd0 and pd1or x11,x11,x7# OR valuessw x11,0(x10)# store in REMAP register#configure GPIO D for I2cla x10,R32_GPIOD_CFGLR# load pointer x10 with address of R32_GPIOD_CFGLR , GPIO configuration registerlw x11,0(x10)# load contents from register pointed by x10li x7,~((0xf<<0)|(0xf<<4))#clear pd1,pd0. pd1,pd0 for I2C remapand x11,x11,x7# clear pd5,pd6,pd1,pd0 mode and cnf bits for selected pin D4,D5,D6li x7,((13<<0)|(13<<4))# pd0,pd1= multiplex opendrain output 10mhzor x11,x11,x7# OR value to registersw x11,0(x10)# store in R32_GPIOD_CFGLR#############I2C0 configurationla x10,R32_RCC_APB1PRSTR# set pointer to clock control peripheral reset registerlw x11,0(x10)# load contents to x11li x7,(1<<21)# shift 1 to 21st bit positionor x11,x11,x7# OR with x11sw x11,0(x10)# set bit 21 of R32_RCC_APB1PRSTR to reset I2C peripheralnot x7,x7# invert values in x7and x11,x11,x7# and x11 to write a 0 in 21st bitsw x11,0(x10)# store 0 in 21st bit to restart i2c enginela x10,R16_I2C_CTLR2# set clock in control 2 registerlh x11,0(x10)# copy contents of R16_I2C_CTLR2 to x11li x7,0xffffffc0# clear frequency bits 0-5 with bit mask 0xffffffc0and x11,x11,x7# AND will clear bit 0-5li x7,(8<<0)# 8Mhz I2C clock .default 24Mhz HSI/3 =8Mhz APB clockor x11,x11,x7# store APB clock frequency in bit 0-5sh x11,0(x10)# store back in R16_I2C_CTLR2la x10,R16_I2C_CKCFGR# set pointer to I2C clockregisterlh x11,0(x10)# copy values to x11 from above registerli x7,0xfffff000# clear CCR bits 0-11 with bitmask 0xfffff000and x11,x11,x7# ANDing clears bit 0-11 in x11 registerli x7,(40<<0)# CCR = t(rscl)+t(wsclh)/tpclk1 = 1000+4000/125 =40 , or (8000000/2*100000)=40 , PCLK/2*100Khz =CCRor x11,x11,x7# store calculated CCR (data sheet)in x11 by ORsh x11,0(x10)# store back in peripheral registerla x10,R16_I2C_CTLR1# set pointer to I2C control register 1lh x11,0(x10)# copy contentsli x7,(1<<0)# 1<<PE = 1<<0 enable bit is bit0,1<<10 is ack enable bitor x11,x11,x7# OR enable bit to x11sh x11,0(x10)# store half word in control register 1la x10,R16_I2C_CTLR1# set pointer to I2C control register 1lh x11,0(x10)# copy contentsli x7,(1<<10)# 1<<10 is ack enable bitor x11,x11,x7# OR ACK enable bit to x11sh x11,0(x10)# store half word in control register 1call I2C_START# send start condition on I2C busli a5,DS1307WAD# radio random read addresscall SEND_ADDRESS# call subroutine to send addressli a5,0x00# clock register 0x00 is set as pointercall I2C_WRITE# call subroutine to transmit value loaded in a0call clock_read# reads 7 bytes from clock registerhere:j here

author: brucehoult
author_rank: Super Contributor
timestamp: February 03, 2025, 10:11:35 pm
content: Yay!I just hope there won't now be a post incoming "I disabled SWIO so I could use the alternate SCL_ output and now I can't reprogram the chip". It's usually the 8 pin package and UTX we hear about because they want to use printf.

author: Sajeev
author_rank: Contributor
timestamp: February 04, 2025, 05:40:28 am
content: Dear Sir,HaHaha!!!I was going to give exactly that update here and I find your message. Yeah doing the above remap disables further programming of the chip. The way to program again is to press the program tab/button in the WCH_UTILITY and reset button on the board (PD7) together multiple times . When the press timing synchronises the chip can be programmed. Might be useful if someone did the same.RegardsSajeev

author: Sajeev
author_rank: Contributor
timestamp: February 10, 2025, 04:10:28 am
content: Dear,i learned that by using "clear all code flash by power off" feature under Target tab of the wch link utility to reprogram and enable the SDWIO feature on PD1 if it was disabled by remapping.Please check picture attached.RegardsSajeev