openwch / arduino_core_ch32

Core library for CH32duino
243 stars 42 forks source link

analogWrite for ch32x035 not working #122

Open arwidcool opened 2 months ago

arwidcool commented 2 months ago

As the title says, no support for analogWrite();

What needs to be done in order for it to work?

Has anyone figured it out?

maxint-rd commented 2 months ago

According to issue #31 it should be working with the latest sources, just not with the latest release (v1.0.4). Have you tried after getting latest commits from this git?

arwidcool commented 2 months ago

It seems like any of the PWM pins using TIM1 causes either no result or actually crashes the MCU.

image

Using PB0 creates junk from serial almost immediately

image

In the setup:

image

arwidcool commented 2 months ago

Update on Pins confirmed NOT working:

PA7, PB1, PC19 (This is SWCLK), PB12,PB3, PB10??(Serial TX) and PB0 is completely messed up causes serial junk when used.

image

mrangen commented 3 weeks ago

I'm struggling to get PWM working as well.

I downloaded the latest version of this repo, unzipped it and used its contents to replace everything in this folder: C:\Users\myusername\AppData\Local\Arduino15\packages\WCH\hardware\ch32v\1.0.4

I still can't get this code to do anything but blink the LED like a digital output. I tried the pins you listed above as working but still no PWM, it's just switches on once it's past 50% duty cycle e.g. 0 to 2050 the LED is off, 2051 to 4095 the LED is on.

Have I missed a step?

image

arwidcool commented 3 weeks ago

@mrangen you seem to be using Arduino IDE. Get it running on PlatformIO @ https://github.com/Community-PIO-CH32V/platform-ch32v

That is what I am using and the mentioned pins work with it. Probably using a different version of the core and maybe buildtools.

mrangen commented 3 weeks ago

@arwidcool thanks, got PWM working now that I'm in PlatformIO, cheers!

maxint-rd commented 3 weeks ago

Currently I only have some models of the CH32V003 to experiment with and have no serious complaints when using the Arduino IDE v2.3.2 . If I had a v035 with such issue, I would first try the same thing out on the v003. (FYI: I just tested a v003 with recent code and had PWM working fine with frequencies as low as 1Hz and as high as about 2MHz)

zwieblum commented 21 hours ago

digitalWrite() on ch32v003 does not work with ArduinoIDE, neither the official 1.0.4 nor the latest git version.

maxint-rd commented 10 hours ago

@zwieblum - hmm... are you sure? digitalWrite() has worked for me in every single release I tried and all my CH32V003 projects use it in various ways. Not having digitalWrite() would make the MCU kind of useless. Are you sure your test environment is setup correctly? Did you try other basic example? What did work and what did not? Can you post the code you've used to test so I can try to reproduce it?

zwieblum commented 8 hours ago

Quite sure. I did not get any pin toggling that is connected to TIM1, e.g. PD0. ch32c003fun pwm timer1 example (PD0) works without a problem for all 4 channels. I did not try pins connected to timer2 in ArduinoIDE. I use ch32v003fun for development, but I would be happy to use the ArduinoIDE for the students. I do not use platformIO.

zwieblum commented 7 hours ago

This works (ArduinoIDE) with PD0:

#define GPIO_CNF_OUT_PP_AF   8
void t1pwm_init( void ) {
  // Enable GPIOC, GPIOD and TIM1
  RCC->APB2PCENR |=   RCC_APB2Periph_GPIOD | RCC_APB2Periph_TIM1;

  // PD0 is T1CH1N, 2MHz Output alt func, push-pull
  GPIOD->CFGLR &= ~(0xf<<(4*0));
  GPIOD->CFGLR |= (GPIO_Speed_2MHz | GPIO_CNF_OUT_PP_AF)<<(4*0);

  // Reset TIM1 to init all regs
  RCC->APB2PRSTR |= RCC_APB2Periph_TIM1;
  RCC->APB2PRSTR &= ~RCC_APB2Periph_TIM1;

  // CTLR1: default is up, events generated, edge align
  // SMCFGR: default clk input is CK_INT

  // Prescaler
  TIM1->PSC = 1024*1024;//0x0000;

  // Auto Reload - sets period
  TIM1->ATRLR = 255;

  // Reload immediately
  TIM1->SWEVGR |= TIM_UG;

  // Enable CH1N output, positive pol
  TIM1->CCER |= TIM_CC1NE | TIM_CC1NP;

  // CH1 Mode is output, PWM1 (CC1S = 00, OC1M = 110)
  TIM1->CHCTLR1 |= TIM_OC1M_2 | TIM_OC1M_1;

  // Set the Capture Compare Register value to 50% initially
  TIM1->CH1CVR = 128;

  // Enable TIM1 outputs
  TIM1->BDTR |= TIM_MOE;

  // Enable TIM1
  TIM1->CTLR1 |= TIM_CEN;
}

void setup() {
  t1pwm_init();
  Serial.begin(115200);
  Serial.println("OK.");
}

int cnt = 0;
void loop() {
  TIM1->CH1CVR=abs(cnt);
  Serial.println(cnt);
  cnt++;
  if(cnt>255) cnt=-255;
  delay(3);
}

This does not work:

int cnt = 0;
void setup() {
  Serial.begin(115200);
  pinMode(PD0,OUTPUT);
}
void loop() {
  Serial.println(cnt);
  digitalWrite(PD0,abs(cnt));
  cnt++;
  if(cnt>255) cnt=-255;
  delay(3);
}
maxint-rd commented 7 hours ago

Okey, so perhaps you could try analogWrite() instead of digitalWrite().
For analogWrite() to work you need:

  1. the most recent source code from the master branch,
  2. the Hardware Timer needs to be enabled in the applicable header file (don't recall the exact name since I modified the board.txt to do it from the the menu)
  3. use a supported pin. In my most recent tests with a SOP16 CH32V003 I found this: PWM SOP16 tested working: PA1/PC0/PC3/PC4 - PWM not working: PC1/PC2/PC6/PC7 (only on/off); PD7=/RST; PA2: always off When a pin is not supported analogWrite() will switch on above 50% and off below 50%.

For my fan controller project I did not do any PWM register configuration directly myself, I only used these:

  pinMode(fan, OUTPUT);
  analogWriteFrequency(100);      // low freq. is much better for driving fan motor
  analogWrite(fan, nSpeed);
zwieblum commented 5 hours ago

Oops, just saw the copy&pase error, too :)

With or without `analogWriteFrequency(100); I get no PWM on any pin. Timer module is enabled by default (it's in the chip definition, TIM_MODULE_ENABLED). Each call to analogWrite() calls pwm_start() which end up reinitialising the timer, but in a way that it is not started.

Did you test on ArduinoIDE or PlatformIO?

maxint-rd commented 4 hours ago

Did you test on ArduinoIDE or PlatformIO?

I'm using Arduino IDE 2.3.2 on Windows 11. I first installed core v1.0.4, then copied newer files over from the master branch and made some changes to boards.txt to let me enable modules using the IDE menu. In my first test I used the Fade example (without setFrequency), then modified it to do some more detailed tests. I measured the default PWM frequency to be 1kHz which was too whiny for a MOSFET driven fan.

This is the bare_minumum example that I adjusted for basic testing/debugging:

int fan = PA1;    // PA1: the PWM pin the fan is attached to 

void setup() {
  // put your setup code here, to run once:
  pinMode(fan, OUTPUT);
  analogWriteFrequency(100);      // low freq. is much better for fan motor; too high causes fan to remain off, default speed 1000 gives whining noise
}

void loop() {
  static int nSpeed=0;
  // put your main code here, to run repeatedly:
  analogWrite(fan, nSpeed); // 8812-4732=4080 bytes for analogwrite!
  if((nSpeed+=10)>4096) nSpeed=0;
  delay(100);
}

I just now tested it to be working (sill). Using the debugger with a breakpoint on the analogWrite() statement, I saw it calling pwm_start() on line 170 of wiring_analog.c. The call to set_pin_configured() on line 167 was done only once, in the first iteration of loop().

Added: within pwm_start() I don't see it re-initialize upon subsequent iterations. The main code executed are these calls on lines 700/701 of analog.cpp:

  HT->setOverflow(PWM_freq, HERTZ_FORMAT);
  HT->setCaptureCompare(channel, value, resolution);

Edit: meant 1.0.4 instead of 1.4

zwieblum commented 2 hours ago

"1.4" or "1.0.4"? Arduino Boardmanager installs 1.0.4, which is identical to the git version. The additional boardmanager URL is https://github.com/openwch/board_manager_files/raw/main/package_ch32v_index.json

The example you gave does not work here.

maxint-rd commented 2 hours ago

"1.4" or "1.0.4"?

Sorry. Meant 1.0.4 indeed; which is the latest release via the board manager indeed. (edited my earlier response). On top of that release you also need all the latest commits related to the hardware timer. Based on your earlier posts I guess you already have those, but apparently it still doesn't work for you. If I were you I'd probably try to trace things in the debugger.

For your information, this is the size of the bare_minimum example above compiled for CH32V003, with hardware timer module enabled and optimized for debugging, with debug symbols:

Sketch uses 9860 bytes (60%) of program storage space. Maximum is 16384 bytes.
Global variables use 436 bytes (21%) of dynamic memory, leaving 1612 bytes for local variables. Maximum is 2048 bytes.

If it's much less bytes for you, you might be missing some core components.

Edit: in addition you may want to remove all your temp compilation files, to ensure all core files (and libraries) are recompiled with the required settings.