HW 8 channel SERVO/MOTOR output on 18F4431 (Oshonsoft)

Thread Starter

camerart

Joined Feb 25, 2013
3,853
Interesting stuff!

I have only just joined so I'm not fully up to speed. I gather that you are driving ESCs and outrunner motors(?)

Are you closing the loop on these motors (QEI) ?

I have used the 18F2331 version as supplied by <Mod Deleted link> on some CNC machines. This chip is able to close the loops and can even directly commutate BLDC motors via LMD18200s. Their NMC (networked machine control) serial protocol is nice :)
Hi T,
Yes, ESCs/motor and SERVO. A Tricopter. This project could be used for other things that need controlling.

I don't know how to use closed loops, but it's a thought. Perhaps later!

At present the plan is:
There are 2x PCBs, both with an 18F46K20 and 18F4431, one is BASE and the other REMOTE.
The BASE will send DATA to REMOTE, which will control the PROPS/SERVO.
C
 

BobTPH

Joined Jun 5, 2013
11,665
I finally dug into the datasheet. Your pic can produce 6 independent PWM signals: 2 via the CCPs and 4 via the PWM module. The 8 outputs of the PWM are 4 complementary pais for driving H bridges.

The PWM module starts with the clock / 4 and can further divide by 64 and a period of 4096, so you can get a frequency if down to 30 Hz, which means 50Hz for servos is achievable.

The CCPs use the clock with a divide by 16 and period if 1024, so min frequency is 1953 Hz, no good for servos.

So you can control only 4 servos at 32Mhz and 6 at 800 KHz.

Bob
 

John P

Joined Oct 14, 2008
2,068
I think he must forget about using the processor's built-in PWM and generate the outputs in software using timer interrupts. It's not too difficult when they only have to operate at 50Hz.
 

Thread Starter

camerart

Joined Feb 25, 2013
3,853
I finally dug into the datasheet. Your pic can produce 6 independent PWM signals: 2 via the CCPs and 4 via the PWM module. The 8 outputs of the PWM are 4 complementary pais for driving H bridges.

The PWM module starts with the clock / 4 and can further divide by 64 and a period of 4096, so you can get a frequency if down to 30 Hz, which means 50Hz for servos is achievable.

The CCPs use the clock with a divide by 16 and period if 1024, so min frequency is 1953 Hz, no good for servos.

So you can control only 4 servos at 32Mhz and 6 at 800 KHz.

Bob
Hi B,
Thanks for looking.

When I read this:
For PMOD0:
1 = PWM I/O pin pair (PWM0, PWM1) is in the Independent mode
0 = PWM I/O pin pair (PWM0, PWM1) is in the Complementary mod
I thought independant meant each pair works seperately.

To help me read D/S more clearly, how did you work out they're not individual. i,e PWM0-7 =8 Channels.
C
 
Last edited:

BobTPH

Joined Jun 5, 2013
11,665
There are only four duty cycle registers. How will you set the duty cycle for your 8 outputs?

I am not sure what they mean by independent mode unless it is just that you can set them high or low independently. I will take another look at that later.

Bob
 

Thread Starter

camerart

Joined Feb 25, 2013
3,853
There are only four duty cycle registers. How will you set the duty cycle for your 8 outputs?

I am not sure what they mean by independent mode unless it is just that you can set them high or low independently. I will take another look at that later.

Bob
Hi B,
I now read this as you do, meaning they are in pairs, so independant MODE both pairs are the same, sadly! (correct me if I'm wrong). Each pair has a setting, to enable a DEAD TIME, for switching purposes.

This means that as you say, 2x CCP and 4PWM Channels.

The earlier suggestion by 'J' is to use an existing program, that switches PWM ON/OFF as a %, by software.
Which is better, the '2 + 4' method or the '%' method?
C
 

jjw

Joined Dec 24, 2013
823
Hi B,
I now read this as you do, meaning they are in pairs, so independant MODE both pairs are the same, sadly! (correct me if I'm wrong). Each pair has a setting, to enable a DEAD TIME, for switching purposes.

This means that as you say, 2x CCP and 4PWM Channels.

The earlier suggestion by 'J' is to use an existing program, that switches PWM ON/OFF as a %, by software.
Which is better, the '2 + 4' method or the '%' method?
C
What do you mean by as a%?.
The program sets the ON times as absolute values 1-2 ms with 1us resolution.
It is in principle what John P says in #43.
 

Thread Starter

camerart

Joined Feb 25, 2013
3,853
Hi,
Thinking about it, CH5 is for extra things, and CH6 which has been introduced is because there is a spare, and could be used later. (I'll change the title to 6)

If the BASE sends 6CH DATA to REMOTE, CH 5 and 6 can be left till later, as only 1-4 are used for flying (which will take a while! I'm sure) I'll have to redisgn the PCB later, but for now, I can cut tracks and re-wire it for testing.

I'll try to get the 4x PWM hardware channels to work first, then if it gets too difficult revert to the 1-2ms program: . [ Unless anyone clarifies that the 1-2ms version is just as good?] https://forum.allaboutcircuits.com/...location-pic-in-oshonsoft.148795/post-1291488
C
 
Last edited:

jjw

Joined Dec 24, 2013
823
The program in the link is the first test, so might have errors.
What do you mean by as good?
I am sure it is easier than using HW Pwm.
 

Thread Starter

camerart

Joined Feb 25, 2013
3,853
The program in the link is the first test, so might have errors.
What do you mean by as good?
I am sure it is easier than using HW Pwm.
Hi J,
It took me a long time to understand the difference between SW and HW, but from what I've learned, it is better to use a PICs HW for any CODE, than SW, so this is why I'm pulling that direction. HW PWM, does look more difficult, but I'm sure I've seen examples to follow, and usually we get there. It would be a shame to waste HW for SW, without a try.

EDIT: I can beat 4 years, that I've puzzled over this! Here's some CODE from 'E' 1984 :https://forum.allaboutcircuits.com/...location-pic-in-oshonsoft.148795/post-1271733 :) Sadly, this is for CCP, so can't be used for 1-4CH here :(
C.
 
Last edited:

Thread Starter

camerart

Joined Feb 25, 2013
3,853
Did not get interrupts.
Hi J,
Ah, the same result as me.
I'm getting used the the program, and will comment all of the registers etc, then I may be able to spot whats blocking it.
There was a suggestion on ETO, that I tried, but no difference.
Thanks for checking.
C
 

jjw

Joined Dec 24, 2013
823
Hi J,
Can you try again please, but change [ CCP1CON = 0x89 ]
C.
Interrupts work now.
To get the pulses out of PORTB
Shift_reg = 1 is needed in the main program before the idle loop.
I looked only the first to pulses and they seem to be ok, but not tested if the timings are correct.
 

jjw

Joined Dec 24, 2013
823
I had faulty results until I added Save System into
interrupt.
As the program is now, the outputs start at Portb.1
not Portb.0
 

Thread Starter

camerart

Joined Feb 25, 2013
3,853
Interrupts work now.
To get the pulses out of PORTB
Shift_reg = 1 is needed in the main program before the idle loop.
I looked only the first to pulses and they seem to be ok, but not tested if the timings are correct.
Hi J,
When you say that you looked at only the first pulses, is this because of the time being too long? If so, then add 'simulation wait value:
Define CONFIG5L = 0x0f
Define CONFIG5H = 0xc0
Define CONFIG6L = 0x0f
Define CONFIG6H = 0xe0
Define CONFIG7L = 0x0f
Define CONFIG7H = 0x40

Define SIMULATION_WAITMS_VALUE = 1

I can test if the timings are correct.
C
 
Last edited:

Thread Starter

camerart

Joined Feb 25, 2013
3,853
I had faulty results until I added Save System into
interrupt.
As the program is now, the outputs start at Portb.1
not Portb.0
Hi J,
This works for me, and I haven't changed Shift_reg = 1

The timing looks suspicious, as they all seem the same looking visually.
C
Code:
'18f4431 20mHz INT REMOTE PWM IR 120522 0901

Define CONFIG1L = 0x00
Define CONFIG1H = 0x02
Define CONFIG2L = 0x0e
Define CONFIG2H = 0x20
Define CONFIG3L = 0x1c
Define CONFIG3H = 0x9d
Define CONFIG4L = 0x80
Define CONFIG4H = 0x00
Define CONFIG5L = 0x0f
Define CONFIG5H = 0xc0
Define CONFIG6L = 0x0f
Define CONFIG6H = 0xe0
Define CONFIG7L = 0x0f
Define CONFIG7H = 0x40

//File:   servo_pwm_test_v2.C
//Author: robert jenkins

//Created On 09 May 2022, 09:45


//Better optimised version, more consistent Output timing And
//no timer Interrupt Or anything needed in main program section,
//beyond the initialisations.

//The main program loop can have delays Or wait loops,
//As Long As interrupts are never blocked.

#define CLOCK_FREQUENCY = 20
ANSEL0 = 0
ANSEL1 = 1

Dim index As Byte

Dim servo_times(8) As Word

Dim time_now As Word
Dim time_set As Word

Dim shift_reg As Byte

//With this timing, 1mS = 1000 counts;
//servo 1mS to 2mS = 1000 to 2000,
//with 1500 as mid point.




//For demonstration, I'm setting the servo times
//to various fixed values.

//Set them from your program as needed.


servo_times(0) = 1100  //Port bit 0, Mid position
servo_times(1) = 1100  //Port bit 1, Near min position
servo_times(2) = 1100  //Port bit 2, Near max position
servo_times(3) = 1500  //Port bit 3, Under mid position
servo_times(4) = 1500  //Port bit 4, Over mid position
servo_times(5) = 1900  //Port bit 5, etc
servo_times(6) = 1900  //Port bit 6
servo_times(7) = 1900  //Port bit 7

TRISB = 0  //Port C all outputs &

T1CON = 0x31  //8:1, switch on

//Without an output pin defined, just an interrupt from CCP
'CCP1CON = 0x02  //ccp_compare_toggle
CCP1CON = 0x89  '&

//And enable the interrupts for the hardware used
//the reference for CCP1, so no time interrupt required.
PIE1.CCP1IE = 1
INTCON1.GIE = 1


//Main loop
loop:

Toggle RD0
WaitMs 500

//Nothing needed here for servos, it's all in the CCP interrupt.
//Rest of the program here onwards.


Goto loop

End                                               

//INT_CCP1
On High Interrupt
Save System

'Break  '<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

shift_reg = ShiftLeft(shift_reg, 1)  //Shift the bit left one place.
//shift_reg = shift_reg + shift reg would do the same.
LATB = shift_reg  //Write the shift register bits to the port &

//Increment index for next servo time value
index = index + 1

If index < 8 Then  //All servos already done?
//No, do next servo

//Set the duration for this output, as a new offset
//from the last compare time.
time_set = time_set + servo_times(index)

CCPR1L = time_set.LB  //Write the compare time to CCP 1 register.
CCPR1H = time_set.HB

Else
//No output needed as the port is already updated.
//output_c(0); // Turn off all servo bits.

//restarting the sequence.

time_set = time_set + 1500  //add 1.5mS for the next interrupt
//Update CCP
CCPR1L = time_set.LB  //Write the compare time to CCP 1 register.
CCPR1H = time_set.HB

If index > 15 Then
//15 * average 1.5mS = 22.5mS, a reasonable frame repeat time

//Set up for a new sequence
index = 0
shift_reg = 1  //Set a bit that will be at port bit 0.

time_now.LB = TMR1L  //Get the timer present count
time_now.HB = TMR1H
time_set = time_now + servo_times(index)  //And set the first duration
LATB = shift_reg  //Write the shift register bits to the port&
CCPR1L = time_set.LB  //Write the compare time to CCP 1 register.
CCPR1H = time_set.HB
Endif
Endif

Resume
 

jjw

Joined Dec 24, 2013
823
I used only three values because the oscilloscope in the simulator shows only four.
I set the fourth as a 1ms tick, 100us on 900us off in the main loop.
I can look the rest separately.

The shift_reg is set to one in the interrupt, when the first 20ms has passed, so I did not want to wait that.

Waitms value does not matter. The interrupt determines most of the simulation time.
 
Top