Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ADC Usage on QFN variant of CH32V003 #110

Open
Audio-Rochey opened this issue Jun 4, 2024 · 19 comments
Open

ADC Usage on QFN variant of CH32V003 #110

Audio-Rochey opened this issue Jun 4, 2024 · 19 comments

Comments

@Audio-Rochey
Copy link

Folks,

I'm trying my best to get the ADC to work, and to simply write it over serial.
`uint16_t adc = 0;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("Ready");

}

void loop() {
// put your main code here, to run repeatedly:
adc = analogRead(PA2);
Serial.print("ADC value is :");
Serial.println(adc);
delay(500);

}`

I've done all the variants mentioned on this group, and enabled the ADC in the variant_CH32V003F4.h file, but I still get a value of zero.

I feel like I'm going nuts here.

@TianpeiLee
Copy link
Collaborator

I switched the sampling channel to A0 (PA_2), and from the serial output, it works fine. It is important to note the pins of the external crystal of PA2.
Perhaps you need to confirm that you are currently using an internal crystal and initialize PA2 as an analog input in the program. ( maybe issue #43 should also check the tested board )

image

uint16_t adc_value=0;
#define ADC_PIN   A0    //003 is PA_2
void setup() 
{
    Serial.begin(115200);
    Serial.printf("%s  Chip ID: 0x%08x\r\n","Hello CH32duino!",DBGMCU_GetDEVID());    
    Serial.printf("system clock %dHz\r\n",SystemCoreClock);
    pinMode(ADC_PIN,INPUT_ANALOG);
}

void loop() 
{
    adc_value = analogRead(ADC_PIN);
    Serial.println(adc_value);

    delay(500);
}

@Audio-Rochey
Copy link
Author

Audio-Rochey commented Jun 4, 2024

Tianpei, thank you, but that code still just gives me 0 data outputs. I have a 5K Ohm Potentiometer between 3V3 and GND, and the wiper going to PA2, I also tried PD4 -- still Zero's.
I have enabled the ADC in the header file that was mentioned in #43.

EDIT: What do you mean by "003 is PA_2"

@maxint-rd
Copy link
Contributor

maxint-rd commented Jun 4, 2024

Have you tried A2 (not PA2) to see what it returns. In issue #94 someone else reported problems with ADC. On the SOP8 package using A2 works for me.

With "003 is PA_2" @TianpeiLee probable meant to say that on the CH32V003 analog pin A0 maps to pin PA_2.
Note however the remarks in issue #94 and perhaps you should also try A2.

@Audio-Rochey
Copy link
Author

Ready to break down in tears here. A2 is one of the few pins I didn't break out, and because it's the QFN variant, it's virtually impossible to get a hold of!
Surely there's a specific register I can write to to switch the input mux appropriately or something?

@maxint-rd
Copy link
Contributor

maxint-rd commented Jun 4, 2024

Hmmm... perhaps there is. I don't have experience in that area.

I did notice you don't call pinMode() in your setup(). In my code I use this:
pinMode(MY_ADC_INPUT, INPUT); // CH32 extension INPUT_ANALOG gives same results as INPUT

Perhaps you can try too, to see if it makes a difference?

Edit: @TianpeiLee has a different call in his example:
pinMode(ADC_PIN,INPUT_ANALOG);
I tried that too but saw it is the same as Arduino compatible "INPUT". I think INPUT_ANALOG is more clear though and perhaps in a future version of this core it may deviate.

@Audio-Rochey
Copy link
Author

Audio-Rochey commented Jun 4, 2024

Current code.

uint16_t adc_value=0;
#define ADC_PIN PIN_A2   //003 is PA_2
void setup() 
{
    Serial.begin(115200);
    Serial.printf("%s  Chip ID: 0x%08x\r\n","Hello CH32duino!",DBGMCU_GetDEVID());    
    Serial.printf("system clock %dHz\r\n",SystemCoreClock);
    pinMode(ADC_PIN,INPUT_ANALOG);
}

void loop() 
{
    adc_value = analogRead(ADC_PIN);
    Serial.println(adc_value);

    delay(500);
}

All Zero's.

Changed to try PD3 and PD4 - no luck. Zero's all round. all day long.

@Audio-Rochey
Copy link
Author

SOLVED IT.
I modified the wrong variant file. I edited the one that was from my previous Arduino 1.xx environment, not my Arduino 2.xx environment.
This helped: https://support.arduino.cc/hc/en-us/articles/4415103213714-Find-sketches-libraries-board-cores-and-other-files-on-your-computer

words cannot describe how frustrated I am. How mad I am, and also how grateful I am to this community. Thank you folks.

@maxint-rd
Copy link
Contributor

Wow, that sounds quite frustrating indeed. Reminds me of the time when I have SPI working on the V003.
Honestly, I think all these defines to enable things should be configurable in the IDE. Since flash memory is quite limited on the V003 I often need to disable things to make it fit. For my recent PR that implements I2C slave mode, I even added another define in twi.h which allows to save some memory. Handling all those defines as menu option in the IDE is still on my wishlist...

@Audio-Rochey
Copy link
Author

or just override those defines in your INO file would be a start.
currently looking through the reference manual for the right register to mux A0 to the ADC etc.
Quietly wishing someone wise from WCH would come help us. Sorting out AnalogRead and AnalogWrite would make quite a difference.

@Audio-Rochey
Copy link
Author

Audio-Rochey commented Jun 4, 2024

some more salt in the wound.
I can define ADC_PIN PIN_A3 or PIN_A4, and they both do conversion from the same pin - pin PD3!

uint16_t adc_value=0;
#define ADC_PIN PIN_A4   //003 is PA_2
void setup() 
{
    Serial.begin(115200);
    Serial.printf("%s  Chip ID: 0x%08x\r\n","Hello CH32duino!",DBGMCU_GetDEVID());    
    Serial.printf("system clock %dHz\r\n",SystemCoreClock);
    pinMode(ADC_PIN,INPUT_ANALOG);
}

void loop() 
{
    adc_value = analogRead(ADC_PIN);
    Serial.println(adc_value);

    delay(100);
}

@Audio-Rochey
Copy link
Author

I'm documenting my hunting here.
There's a register on the device called "AFIO_PCFR1" - it has 2 bits that can remap PA1 and PA2 away from oscillators (assuming using the internal one).
ch32v00x.h has the following line in it:
#define AFIO_PCFR1_PA12_REMAP ((uint32_t)0x00008000) /* Port D0/Port D1 mapping on OSC_IN/OSC_OUT */

From the reference manual 
"Pin PA1 & PA2 remapping bit, this bit can be read or written by user. It controls the proper function of PA1 and PA2 (set to 1 when connected to an external crystal pin)
0: Pin is used as GPIO and multiplexed function
1: No functional role for pins"

I'm getting close here... I can feel it.

@maxint-rd
Copy link
Contributor

Good going. Looking at the other issues regarding ADC, I think you're not the only one. I spent quite some time to get reading VCC by using PADC_VREF working and only managed that by butchering some original code. See this branch of my CH32 fork.

From what I read in issue #94, it seemed pins used for oscillator may behave differently. Somewhere deep down there may be some logic. (While getting I2C slave working I found the realtime debugger to be crucial in gaining some understanding).

BTW. Different type of pin names can obfuscate things even more, e.g. A2 / PA2 / PIN_A2.

@Audio-Rochey Audio-Rochey reopened this Jul 5, 2024
@Audio-Rochey
Copy link
Author

Hello folks,
@TianpeiLee was kind enough to send me a message back via email too.
The code example I received was the same as the one shared on June 3rd.
He also showed an additional config in the arduino ide that lets you select the clock source. I think @maxint-rd did some work on that, but the 1.0.4 doesn't have it visible by default.

I have enabled the ADC in the variant .h file, and I've now set the clock source to 48MHz HSI (assuming HSI = internal?)

On A3 (PD2) I now get values. (connecting to VCC I get 1024, and GND = 0)
On A0, with the same code (other than ADC input definition of A0), the values at VCC are ~350, with small fluctuations. Connecting to GND give the same value. Leaving it floating leaves values of ~330.

My ADC clearly works, but when A0 is selected.
I think I'm missing something with an internal mux.

@Audio-Rochey
Copy link
Author

Another day, another update!

I downloaded this codebase and overwrote the 1.0.4 release with it. (July 8th 2024)
I see the CH32VM00x devices as well, and when they are selected, I can see the clock select.
However, when the CH32V00x is selected, I still don't see the clock select.

Regardless, I went to the appropriate system_ch32v00x.c and uncommented the 48MHz HSI clock source.
With PA2 connected to 3.3V, I get 3 consecutive values: 540, 515, 490.
Same when left floating.
There's some variance when grounded, but not much.

Once again, I'm left thinking that the mux is to blame here.
Is there a way to speak directly to the input mux register within my arduino code?

/Dafydd

@TianpeiLee
Copy link
Collaborator

The default function of PA1 and PA2 is the IO port, and the floating input in the default state of the IO port can also be sampled to obtain the ADC value. Theoretically, when using the internal HSI, it can get the value via channel 1 and channel 0 of ADC without doing anything to this IO port.

@Audio-Rochey
Copy link
Author

@TianpeiLee Thank you for the response.
I don't understand why I'm not getting good data on the ADC then!
I used your code. (your simple adc to serial!)
I used the code from this github and still I get junk data when I connect A0 to 3V3 and 0V.

Do you have a binary code that I can use to download to the device, so I can work out if it's a HW issue or a toolchain issue?

@TianpeiLee
Copy link
Collaborator

build.zip
@Audio-Rochey This is my compilation result.

@amgrays
Copy link

amgrays commented Jul 18, 2024

I have been battling the ADC this week and have finally resolved the issue. It is not exactly related to the specific topic (QFN variant) but could well be relevant. My setup is:

  • Target chip is CH32V003J4M6 (8pin SOIC)
  • Development environment - MounRiver Studio
  • Trying to use all 5 available I/O pins and happened to select pin#3 (PA2/A0) for analogue input

Problem: I could not get anything sensible from the analogue input port despite looking at about 3 different examples (BTW I found them overly complicated - using timers to trigger, using interrupts etc.) A basic example should just do a standard software read IMHO). Also tried another pin (PC4/A2) - results were better but quite a significant amount of "noise" on the output.

Solution: The default startup code is designed to run on the evaluation board which uses an external crystal attached to PA1/PA2 of the CH32V003F4P6 device. There is a set of defines at the top of system_ch32v00x.c (under User folder) which configures this. For the EVB, SYSCLK_Freq_48MHz_HSE is used but for any other variant NOT using an external crystal, you would need to change it to one of the ones ending in "HSI". My guess is that this initial config gets "locked" and so if you try writing the bit in the AFIO register later that controls PA1/PA2 use for the crystal, or even change the firmware with the programmer, it is not effective until you power cycle the device. You have to compile with the right define, program the device, then power cycle.

The other point to note is that I noticed some really odd waveforms on the A2 pin during the process of trying to work out what was going on. I had used PD6 connected to pin 1 (also used for PA1 on the 8-pin device) as an output to an LED. The signal sent to PD6 (flashing the LED) was superimposed on the analog input pin which explained the erratic (noisy) readings I was getting on A2. Suffice it to say that once I stopped the firmware trying to use PA1/PA2 for an external crystal, my woes have disappeared and the ADC is reading very nicely.

I hope this helps someone :)

@maxint-rd
Copy link
Contributor

maxint-rd commented Jul 19, 2024

@amgrays - Excellent work! I admire your persistance in figuring out the root cause of your issue.

FYI: in later versions of this core the clock selection is done in the IDE menu. I ran into clock issues months ago when I noticed that delay was off a factor of two when ran on bare chips. To fix that issue was one of my first priorities and a PR for that has been merged (but maybe not in release 1.0.4).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants