openwch / arduino_core_ch32

Core library for CH32duino
256 stars 43 forks source link

ADC Usage on QFN variant of CH32V003 #110

Open Audio-Rochey opened 4 months ago

Audio-Rochey commented 4 months ago

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 commented 4 months ago

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 commented 4 months ago

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 commented 4 months ago

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 commented 4 months ago

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 commented 4 months ago

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 commented 4 months ago

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 commented 4 months ago

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 commented 4 months ago

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 commented 4 months ago

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 commented 4 months ago

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 commented 4 months ago

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 commented 4 months ago

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 commented 3 months ago

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 commented 3 months ago

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 commented 2 months ago

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 commented 2 months ago

@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 commented 2 months ago

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

amgrays commented 2 months ago

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:

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 commented 2 months ago

@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).