Closed odo2063 closed 6 years ago
According to the pins_arduino.h for that board there is one PWM ouput on pin 8 (P0.5) so like Arduino Uno the analog o/p is actually a PWM output.
This is board PHYSICAL pin 16 (top right on pin out diagram on the wiki)
Yes, there is one PWM output pin as already said.
So this should work with analogWrite()
as expected.
If you face any issues, please let me know.
Best regards,
Manuel
ok, so you maybe want to add the "~" in the pinoutdiagramm? ;-)
Hi Manuel,
would it be possible to add the "analogWriteFrequency(float Hz)" -Funktion (like in teensyduino) in the next release?
Some time ago i played with Dave-App for PWM, looking for a possibility to create 1,5Hz blink-frequency, and with small modifications in the generated "pwm.h" and "pwm.c" - files , it was possible to generate (ultra) low pwm-frequency (down to 0,03Hz)
PCLK =64MHZ PRESCALER = 1 << 15 (2^15) PERIODVALUE = 65535
-->> lowest possible PWM frequency = 0,0298027771 Hz (with 65535 Resolution)
with this mod :
change type of pwm_frq_hz from uint32 to float
;-)
/Sets the frequency for CCU4 slice. / PWM_STATUS_t PWM_lCCU4_SetFreq(PWM_t *const handle_ptr, float pwm_freq_hz) { PWM_STATUS_t status; uint32_t module_freq; uint8_t prescaler; uint32_t period_value; uint32_t compare;
regards Hubert
Personally I try to avoid floats like the plague, as the overheads of floats is large.
Work with remainders or fixed point maths is ually faster and more accurate
That was just a "quick&dirty" modification of the DAVE function , inspired by the arduino-teensy 3.x lib. the teensy 3.2 has a Cortex M4 MCU (MK20DX256)
same result could be reached by adding an additional parameter like "uint_8 precision" :
PWM_STATUS_t PWM_lCCU4_SetFreq(PWM_t *const handle_ptr, uint32_t pwm_freq_hz, uint8_t precision)
maybe something like this:
..... // set 1,23 Hz PWM_SetFreq(&_PULSE,123,PWM_PRECISION_2);
for Arduino-compatibility it should look like analogWriteFrequency( pmw_pin ,123 , PWM_PRECISION_2 );
But i think the Arduino-way is rather to have a quick result for an idea ,with easy to use functions, than to produce highly efficient code..
Quite a lot of Arduino way is ignore errors, discard data on incoming data and many other issues.
I am trying to see if XMC-for-Arduino could be usable for educational projects with 17-18 year old school projects. Most of the things I am looking are for what the students would use and if some of my standard libraries could be ported to assist their projects.
Things like better LCD library, task scheduling, PS2 interfaces, DMX controller and device operations. Personally better timer handling and functions like micros and delaymicroseconds working properly and without issues from disabling interrupts are more important, than VLF PWM, as these are used in nearly all the projects I have seen over the years.
Other than proof of concept of a PART of a commercial project I would MIGHT use XMC-for-Arduino, having found the issues in these libraries I will be looking at what also exist in Dave for fuller projects,. That may be a way off as I need efficient code as some of my systems run continuously for years or do relatively high speed operations for the processor speed sometimes with dedicated FPGAs
"analogWriteFrequency(int32 Hz)" would also be ok XD....or is there another way to set the frequency?
By not using Hz as the units but ms or us as the units as the time period for cycle is what the timers use, consider a 32 bit value for us and the range that has. However many of the timers on many platforms do not have 32 bit timer/counters.
What can be done depends on the limits of the platform not what a piece of software can processs. realistically if you really want VLF PWM you can also do that by GPIO toggling and delay() with ms timings. This assumes you are not doing anything else as the majority of Arduino style functions are linear and not good at doing much in parallel with hardware assist.
Can someone please give me an example on how to change the PWM frequency for xmc2go?
Hi odo2063,
seems Manuel was very busy yesterday ;-))
i saw this morning that there is a new branch "XMCLib" https://github.com/Infineon/XMC-for-Arduino/blob/xmclib/arm/cores/wiring_analog.c if you take a look to the wiring_analog files, there is a new function that should do the job:
extern int16_t setanalogWriteFrequency( uint8_t pin, uint32_t frequency )
regards Hubert
odo2063:
ok, so you maybe want to add the "~" in the pinoutdiagramm? ;-)
I added a line indicating a "~" to the pin out diagrams.
As already found out, PWM frequency change has been implemented, but we need to test it/rework it. For the PWM frequency changes, the pull requests as well as additional points, I need to work on it.
I will add a new issue tomorrow for proper discussion of the new release and reference related issues. By this, I hope to merge all requests and changes in a proper way to a new final release.
Thank you very much for all your feedback and work, very much appreciated!
Best regards,
Manuel
What PWM frequency, resolution andaccuracy do you need?
Recent changes I have done to tone and wiring_time could easily do VVLF frequency toggle of GPIO, in 1 ms steps which means you could have a VERY VERY LOW frequency but specify the ON and OFF times in ms with limits of
Min ON or Min OFF 1 ms Max ON or Max OFF approx 50 years
1.23 Hz is 813 ms period so by specifying ON and OFF times on the fly you could have a 812 steps of PWM variation to 1ms accuracy, about 9.5 bits of resolution and accuracy Whilst still having lots of processing time available..
At even slower PWM frequency you have more bits of resolution and accuracy
Function like
LFPWM_mode( pin, uint8_t Start level )
LFPWM_time(uint32_t ON, uint32_t OFF )
If this would help I can see in betwen other paying work and other fixes if this can be added
Hi Manuel, i made some test this evening with an XMC2Go and checked the frequency an dutycycle with an Osziloscop. there where some deviation in frequency and duty cycle. above 1000Hz it didnt work.
i made some small modificatin in the function to calculate prescaler and timer period , with that it is working better, the deviation is now below 0,1% in the range from 100Hz to 100kHz. (according to the frecuency-counter on my scope)
extern int16_t setanalogWriteFrequency( uint8_t pin, uint32_t frequency ) { int16_t ret = -1; XMC_CCU4_SLICE_PRESCALER_t prescaler = (XMC_CCU4_SLICE_PRESCALER_t) 0; if(frequency < PCLK) { uint8_t exp = 0u; do { //if(frequency > PCLK/(1u<<exp)) //**** if(frequency >= ((PCLK >> exp)/65536)) //**** { break; } exp++; }while(exp <= 12u);
if (digitalPinHasPWM4(pin))
{
uint8_t pwm4_num = digitalPinToPWM4Num(pin);
XMC_PWM4_t *pwm4 = &mapping_pwm4[pwm4_num];
pwm4->prescaler = exp;
//pwm4->period_timer_val = PCLK/(frequency*(1u<<exp));
// pwm4->period_timer_val = ((PCLK >> exp)/frequency)-1; // //
if(pwm4->enabled == ENABLED)
{
// Disable pwm output
pwm4->enabled = DISABLED;
XMC_CCU4_SLICE_StartTimer(pwm4->slice);
}
ret = 0;
}
else if (digitalPinHasPWM8(pin))
{
uint8_t pwm8_num = digitalPinToPWM8Num(pin);
XMC_PWM8_t *pwm8 = &mapping_pwm8[pwm8_num];
pwm8->prescaler = exp;
//pwm8->period_timer_val = PCLK/(frequency*(1u<<exp));
pwm4->period_timer_val = ((PCLK >> exp)/frequency)-1;
if(pwm8->enabled == ENABLED)
{
// Disable pwm output
pwm8->enabled = DISABLED;
XMC_CCU4_SLICE_StartTimer(pwm8->slice);
}
ret = 0;
}
}
return ret;
}
regards Hubert
did not work in range 1-10Hz at 1,3,7 Hz
//**** if(frequency >= ((PCLK >> exp)/65536)) //**** removing the "=" here solved it.
if(frequency > ((PCLK >> exp)/65536))
Hi Paul,
for current projekt i need low frequencies up to max 5 kHz for building a testequipment for aftermarkert motorcycle-speedo to simulate speed- (0..300kmh , ->0....83,33Hz) and rpm (0..18000 /min, -> 0...300Hz) -signals
the frequency also can be higher , depending on the pulses per meter ( 1... 64) and rpm (1..4), depending on the bike setup.
Personally it is not the maximum frequency that is the problem it is resolution, as soon as you use a counter for PWM you lose resolution in frequency depending on numbers of bits need to handle the PWM.
Realistically whatever the frequency to maintain corect pulses (as if from hal effect or opto slotted wheel or similar) you need to maintain the mark/space ratio. to do that on XMC1xxxx CCU4 module and maintain the mark/space ACCURACY over the full range, you would probably need to use a cascaded PWM of 32 bit width. Then comes the problem of adjusting frequency and PWM values on cascaded units without glitches.
If on one configuration you need a 1:63 mark/space ratio, you need to clock 64 x faster at least if not 1024 times to maintain PWM range with frequency to avoid quantisation errors.
For this sort of thing I would borrow a thought from engine management micros and their Timing Pattern Units, where they change ONLY the frequency of update as the timing pattern is repeated often many bits wide giving parrallel shift registers many ouput serial bits wide, to keep things in sync.
By having an external 16 bit or more, Parallel In Serial Out shift register you can shift out a pattern until it recives the first one then reload the shift register, giving you a constant 1:16 (or however many bits wide), mark/space ratio. Then concentrate on using the micro to use 16 or 32 bit counter to produce an accurate frequency sweep over the range.
Timers have problems at low and high ends of range as to how much deviation is acheived per bit change. Top frequencies have large jumps in frequency, whilst at low end large count differences are required to make a change within your desired range. The difference between 1 Hz and 1.1 Hz can be large.
Changing prescalers adds other issues of needing hysterisis in when you change with overlapping calaculation ranges to allow for changes smoothly.
I would personally use external shift registers in a Timing Pattern Unit mode or build larger width TPU into a PLD/FPGA to be configurable and accurate. Concentrating on speed control from the micro by accurate clock over the range.
This is an example circuit of what I mean by shift registers
Thanks for all the information provided here. i made some more tests with different boards,
in made a small modification in calulation for the timer period to increase the accuraty (a little)
//***
// modified calulation of timer period
uint16_t period = (PCLK >> prescaler ) / frequency // ;PCLK / ( ( 1U << prescaler ) * frequency) ; // - 1;
//***
int16_t resource;
if ( ( resource = scan_map_table( mapping_pin_PWM4, pin ) ) >= 0 )
{
uint8_t pwm4_num = resource;
XMC_PWM4_t *pwm4 = &mapping_pwm4[pwm4_num];
pwm4->prescaler = prescaler;
pwm4->period_timer_val = period; //PCLK / ( ( 1U << prescaler ) * frequency) - 1;
if(pwm4->enabled == ENABLED)
{
// Disable pwm output
pwm4->enabled = DISABLED;
XMC_CCU4_SLICE_StartTimer(pwm4->slice);
}
ret = 0;
}
with that it is very accurate on XMC4700 board. i tested a funtion to set frequency with precission e.g 100.00 wich work good for lower frequency up to 1kHz: // set frequency with 0.01 resolution extern int16_t setAnalogWriteFrequency100( uint8_t pin, uint32_t frequency ) { uint32_t freq = frequency/100; uint16_t period ;
int16_t ret = -1;
if(freq < PCLK)
{
uint16_t prescaler = 0U;
do
{
if( freq > (PCLK / ( ( 1U << prescaler ) * 65536U )) )
{
break;
}
prescaler++;
}while(prescaler < 16);
period = (PCLK >> prescaler )*100 / frequency ;
int16_t resource;
if ( ( resource = scan_map_table( mapping_pin_PWM4, pin ) ) >= 0 )
{
uint8_t pwm4_num = resource;
XMC_PWM4_t *pwm4 = &mapping_pwm4[pwm4_num];
pwm4->prescaler = prescaler;
pwm4->period_timer_val = period; // (PCLK >> prescaler )*100 / frequency ;//- 1;
if(pwm4->enabled == ENABLED)
{
// Disable pwm output
pwm4->enabled = DISABLED;
XMC_CCU4_SLICE_StartTimer(pwm4->slice);
}
ret = 0;
}
. . . regards Hubert
Is it possible to use analogWrite() with the XMC2go?