Author Topic: CH32V003 I2C remap not working  (Read 1604 times)

0 Members and 1 Guest are viewing this topic.

Offline SajeevTopic starter

  • Contributor
  • Posts: 31
  • Country: in
CH32V003 I2C remap not working
« on: February 03, 2025, 07:55:46 am »
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: [Select]
#include CH32V003_reg.S
.align 4
.text
.global start
start:
sp_init:
    la sp, STACK # initialize stack pointer

#Enable GPIO clocks & AFIO in APB2 clock register
       
    la x10,R32_RCC_APB2PCENR # load address of APB2PCENR register to x10 ,for enabling GPIO A,D,C peripherals
lw x11,0(x10) # load contents from peripheral register R32_RCC_APB2PCENR pointed by x10
li 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 functions
or x11,x11,x7 # or values
sw x11,0(x10) # store modified enable values in R32_RCC_APB2PCENR
#Enable I2C clock in  APB1 register
   
    la x10,R32_RCC_APB1PCENR # load address of APB1PCENR register to x10 ,for enabling I2C peripheral
lw x11,0(x10) # load contents from peripheral register R32_RCC_APB1PCENR pointed by x10
li x7,(1<<21) # 1<<I2C1_EN, = 1<<21 for I2C functions
or x11,x11,x7 # or values
sw x11,0(x10)

#I2C remap from pc1,pc2 to pd0,pd1

la x10,R32_AFIO_PCFR1
lw x11,0(x10)
li x7,((0<<22)|(1<<1)) # 01 in 22 and 1 bits will remap i2c to pd0 and pd1
or x11,x11,x7
sw x11,0(x10)

#configure GPIO D for  I2c
la x10,R32_GPIOD_CFGLR # load pointer x10 with address of R32_GPIOD_CFGLR , GPIO configuration register
lw x11,0(x10) # load contents from register pointed by x10
li x7,~((0xf<<4)|(0xf<<0)) #clear pd1,pd0. we need to setup  pd1,pd0 for I2C remap
and x11,x11,x7 # clear pd5,pd6,pd1,pd0 mode and cnf bits for selected pin D4,D5,D6
li x7,((13<<4)|(13<<0)) # multiplex open drain 10MHZ on PD0 and PD1
or x11,x11,x7 # OR value to register
sw x11,0(x10) # store in R32_GPIOD_CFGLR

############
#I2C0 configuration
la x10,R32_RCC_APB1PRSTR # set pointer to clock control  peripheral reset register
lw x11,0(x10) # load contents to x11
li x7,(1<<21) # shift 1 to 21st bit position
or x11,x11,x7 # OR with x11
sw x11,0(x10) # set bit 21 of R32_RCC_APB1PRSTR to reset I2C peripheral
not x7,x7         # invert values in x7
and x11,x11,x7 # and x11 to write a 0 in 21st bit
sw x11,0(x10) # store 0 in 21st bit to restart i2c engine

la x10,R16_I2C_CTLR2 # set clock in control 2 register
    lh x11,0(x10) # copy contents of R16_I2C_CTLR2 to x11
li x7,0xffffffc0         # clear frequency bits 0-5 with bit mask 0xffffffc0
and x11,x11,x7 # AND will clear bit 0-5
    li x7,(8<<0) # 8Mhz I2C clock .default 24Mhz HSI/3 =8Mhz APB clock
    or x11,x11,x7 # store APB clock frequency in bit 0-5
sh x11,0(x10) # store back in R16_I2C_CTLR2
    la x10,R16_I2C_CKCFGR # set pointer to I2C clockregister
    lh x11,0(x10) # copy values to x11 from above register
li x7,0xfffff000         # clear CCR bits 0-11 with bitmask 0xfffff000
and x11,x11,x7 # ANDing clears bit 0-11 in x11 register
li x7,(40<<0) # CCR = t(rscl)+t(wsclh)/tpclk1 = 1000+4000/125 =40 , or (8000000/2*100000)=40 , PCLK/2*100Khz =CCR
    or x11,x11,x7 # store calculated CCR (data sheet)in x11 by OR
sh x11,0(x10) # store back in peripheral register
la x10,R16_I2C_CTLR1 # set pointer to I2C control register 1
lh x11,0(x10) # copy contents
li x7,(1<<0) # 1<<PE = 1<<0 enable bit is bit0,1<<10 is ack enable bit
or x11,x11,x7 # OR enable bit to x11
sh x11,0(x10) # store half word in control register 1
la x10,R16_I2C_CTLR1 # set pointer to I2C control register 1
lh x11,0(x10) # copy contents
li x7,(1<<10) # 1<<10 is ack enable bit
or x11,x11,x7 # OR ACK enable bit to x11
sh x11,0(x10) # store half word in control register 1

 

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4965
  • Country: nz
Re: CH32V003 I2C remap not working
« Reply #1 on: February 03, 2025, 08:34:03 am »
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)
 

Offline SajeevTopic starter

  • Contributor
  • Posts: 31
  • Country: in
Re: CH32V003 I2C remap not working
« Reply #2 on: February 03, 2025, 08:43:17 am »
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.
Rgards
Sajeev
 

Offline SajeevTopic starter

  • Contributor
  • Posts: 31
  • Country: in
Re: CH32V003 I2C remap not working
« Reply #3 on: February 03, 2025, 08:49:55 am »
Dear,
I am using CH32v003F4U6  TSSOP20 chip . 20 pin version. regrets for the omission.
Regards
Sajeev
 

Offline SajeevTopic starter

  • Contributor
  • Posts: 31
  • Country: in
Re: CH32V003 I2C remap not working
« Reply #4 on: February 03, 2025, 11:30:03 am »
looks like ill have to bitbang I2C if remap not possible
Sajeev
 

Offline SajeevTopic starter

  • Contributor
  • Posts: 31
  • Country: in
Re: CH32V003 I2C remap not working
« Reply #5 on: February 03, 2025, 03:43:52 pm »
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 for
SW function and trace function. SWD (SDI) is the
debug interface to access the core. It is always
used as a SWD port after system reset.
0xx: SWD (SDI) enabled.
100: Turn off SWD (SDI), which functions as a
GPIO.
Others: Invalid."



Thanks for the response.
regards
Sajeev

The working remapped code for pd0,pd1 is as below
Code: [Select]
.align 4
.text
.global start
start:
sp_init:
    la sp, STACK # initialize stack pointer

#Enable GPIO clocks & AFIO in APB2 clock register
       
    la x10,R32_RCC_APB2PCENR # load address of APB2PCENR register to x10 ,for enabling GPIO A,D,C peripherals
lw x11,0(x10) # load contents from peripheral register R32_RCC_APB2PCENR pointed by x10
li 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 functions
or x11,x11,x7 # or values
sw x11,0(x10) # store modified enable values in R32_RCC_APB2PCENR
#Enable I2C clock in  APB1 register
   
    la x10,R32_RCC_APB1PCENR # load address of APB1PCENR register to x10 ,for enabling I2C peripheral
lw x11,0(x10) # load contents from peripheral register R32_RCC_APB1PCENR pointed by x10
li x7,(1<<21) # 1<<I2C1_EN, = 1<<21 for I2C functions
or x11,x11,x7 # or values
sw x11,0(x10)

#I2C remap from pc1,pc2 to pd0,pd1

la x10,R32_AFIO_PCFR1 # load address of REMAP register
lw x11,0(x10) # copy contents
li 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 pd1
or x11,x11,x7 # OR values
sw x11,0(x10) # store in REMAP register





#configure GPIO D for I2c
la x10,R32_GPIOD_CFGLR # load pointer x10 with address of R32_GPIOD_CFGLR , GPIO configuration register
lw x11,0(x10) # load contents from register pointed by x10
li x7,~((0xf<<0)|(0xf<<4)) #clear pd1,pd0.  pd1,pd0 for I2C remap
and x11,x11,x7 # clear pd5,pd6,pd1,pd0 mode and cnf bits for selected pin D4,D5,D6
li x7,((13<<0)|(13<<4)) # pd0,pd1= multiplex opendrain output 10mhz
or x11,x11,x7 # OR value to register
sw x11,0(x10) # store in R32_GPIOD_CFGLR




############
#I2C0 configuration
la x10,R32_RCC_APB1PRSTR # set pointer to clock control  peripheral reset register
lw x11,0(x10) # load contents to x11
li x7,(1<<21) # shift 1 to 21st bit position
or x11,x11,x7 # OR with x11
sw x11,0(x10) # set bit 21 of R32_RCC_APB1PRSTR to reset I2C peripheral
not x7,x7         # invert values in x7
and x11,x11,x7 # and x11 to write a 0 in 21st bit
sw x11,0(x10) # store 0 in 21st bit to restart i2c engine

la x10,R16_I2C_CTLR2 # set clock in control 2 register
    lh x11,0(x10) # copy contents of R16_I2C_CTLR2 to x11
li x7,0xffffffc0         # clear frequency bits 0-5 with bit mask 0xffffffc0
and x11,x11,x7 # AND will clear bit 0-5
    li x7,(8<<0) # 8Mhz I2C clock .default 24Mhz HSI/3 =8Mhz APB clock
    or x11,x11,x7 # store APB clock frequency in bit 0-5
sh x11,0(x10) # store back in R16_I2C_CTLR2
    la x10,R16_I2C_CKCFGR # set pointer to I2C clockregister
    lh x11,0(x10) # copy values to x11 from above register
li x7,0xfffff000         # clear CCR bits 0-11 with bitmask 0xfffff000
and x11,x11,x7 # ANDing clears bit 0-11 in x11 register
li x7,(40<<0) # CCR = t(rscl)+t(wsclh)/tpclk1 = 1000+4000/125 =40 , or (8000000/2*100000)=40 , PCLK/2*100Khz =CCR
    or x11,x11,x7 # store calculated CCR (data sheet)in x11 by OR
sh x11,0(x10) # store back in peripheral register
la x10,R16_I2C_CTLR1 # set pointer to I2C control register 1
lh x11,0(x10) # copy contents
li x7,(1<<0) # 1<<PE = 1<<0 enable bit is bit0,1<<10 is ack enable bit
or x11,x11,x7 # OR enable bit to x11
sh x11,0(x10) # store half word in control register 1
la x10,R16_I2C_CTLR1 # set pointer to I2C control register 1
lh x11,0(x10) # copy contents
li x7,(1<<10) # 1<<10 is ack enable bit
or x11,x11,x7 # OR ACK enable bit to x11
sh x11,0(x10) # store half word in control register 1

call I2C_START         # send start condition on I2C bus
li a5,DS1307WAD         # radio random read address
call SEND_ADDRESS         # call subroutine to send address
li a5,0x00                 # clock register 0x00 is set as pointer
call I2C_WRITE         # call subroutine to transmit value loaded in a0
call clock_read                 # reads 7 bytes from clock register
here:
j here

« Last Edit: February 03, 2025, 03:53:31 pm by Sajeev »
 

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4965
  • Country: nz
Re: CH32V003 I2C remap not working
« Reply #6 on: February 03, 2025, 10:11:35 pm »
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.
 

Offline SajeevTopic starter

  • Contributor
  • Posts: 31
  • Country: in
Re: CH32V003 I2C remap not working
« Reply #7 on: February 04, 2025, 05:40:28 am »
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.
Regards
Sajeev ;D ;D ;D ;D
 
The following users thanked this post: voltsandjolts, mikerj

Offline SajeevTopic starter

  • Contributor
  • Posts: 31
  • Country: in
Re: CH32V003 I2C remap not working
« Reply #8 on: February 10, 2025, 04:10:28 am »
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.
Regards
Sajeev
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf