18f26k80 with PWM

Discuss PIC and electronic related things

Moderators: David Barker, Jerry Messina

richardb
Posts: 310
Joined: Tue Oct 03, 2006 8:54 pm

18f26k80 with PWM

Post by richardb » Tue Jul 05, 2011 11:35 am

Hi i hope somone can help me.

I've been trying to use a pic 18f26k80 with pwm on 2 outputs and I'm struggling

id like to get a pwm output on pin 13(PORTC.2/ccp2) and pin25 (PORTB.4/eccp1)

and i can only seem to get a pwm output on PORTB.4.

I've been hunting through the data sheets and just cant seem to get it working.

Code: Select all

Device = 18F26k80
Clock = 64
 Config FOSC = HS2        'HS2 = set to high speed osc
 Config PLLCFG = ON
 Config SOSCSEL = DIG     'set c.0 and c.1 to digital
 
Include "HPWM2.bas"

Include "utils.bas"

Dim led As PORTC.0 // this is pin 7 board needs changing !

     CCPTMRS = %00000000
    Utils.SetAllDigital()
    CM1CON = %00000100
    CM2CON = %00000100
    ANCON0 = %00000101
    ANCON1 = %00000000
    TRISA = %11110101
    TRISB = %11111111 
    TRISC = %10111000 
   { T1CON.3 = 0
    T3CON.3 = 0  }
    ADCON1 = %01000000  
    PWM2.SetFreq(10000)
    PWM2.Start1
    PWM2.Start2
    
    PWM2.SetDuty1(50)
    PWM2.SetDuty2(60)
    

While true
    DelayMS(100)
    Toggle(led)    
Wend   
End

Code: Select all

                                                                                                                
Module PWM2
Device = 18F26k80
Dim
   FMaxDuty As Word,
   FTMR2ON As T2CON.2

   Dim FPWM1Pin As PORTB.4    
   Dim FPWM2Pin As PORTC.2   
   

Public Sub Start1()
    CCP1CON = $0C
    Output(FPWM1Pin) 
    FTMR2ON = 1   
End Sub

Public Sub Start2()
    CCP2CON = $0C
    Output(FPWM2Pin) 
    FTMR2ON = 1   
End Sub

	
Public Sub SetDuty1(pDuty As Word)
   CCP1CON.5 = pDuty.1
   CCP1CON.4 = pDuty.0	
   CCPR1L = pDuty >> 2
End Sub
	
Public Sub SetDuty2(pDuty As Word)
   CCP2CON.5 = pDuty.1
   CCP2CON.4 = pDuty.0	
   CCPR2L = pDuty >> 2
End Sub

{
****************************************************************************
* Name    : MaxDuty                                                        *
* Purpose :                                                                *
****************************************************************************
}   
Public Inline Function MaxDuty() As FMaxDuty
End Function
{
****************************************************************************
* Name    : SetFreq                                                        *
* Purpose :                                                                *
* Notes   : Initializes Freq settings                                      * 
*         : Resets Duty Cycle To 0                                         *
*         : Requires PWM.Start afterward if PWM is not running             *               
****************************************************************************
} 
Public Function SetFreq(pFrequency As LongWord) As Boolean
   Const Fosc As LongWord = _clock * 1000000
   Dim Prescale As Byte
   Dim PR2Value, PRConst As Word

   // loop through all the valid prescalers...
   PRConst = Fosc / pFrequency / 4
   Prescale = 1
   Result = false
   Repeat
      PR2Value = PRConst / Prescale - 1        // calculate a PR2 value
      If PR2Value < 256 Then                   // if it is a valid value, then... 
         FMaxDuty = (PR2Value + 1) * 4         // determine maximum duty... 
	 PR2 = PR2Value                        // initialise PR2                 
         Select Prescale                       // configure T2CON prescale
            Case 1  : Prescale = %00000000     // prescale 1
	    Case 4  : Prescale = %00000001     // prescale 4
	    Case 16 : Prescale = %00000011     // prescale 16
         End Select
         SetDuty1(0)                           // output = 0V
         SetDuty2(0)                           //
         T2CON = (T2CON And 252) Or Prescale   // load prescaler value
         Result = true                         // function return true (success)         
         Exit                                  // exit the sub
      EndIf   
      Prescale = Prescale * 4
   Until Prescale > 16
End Function
{
****************************************************************************
* Name    : SetFreqByTable                                                 *
* Purpose : Change PWM frequency settings by indexing table                *
* Notes   : Initializes Freq settings                                      * 
*         : Resets Duty Cycle To 0                                         *
*         : Requires PWM.Start afterward if PWM is not running             *               
****************************************************************************
}
Public Sub SetFreqByTable(pIndex As Byte)
 Const pwmtbl(4) As Byte = (255,1,127,3)
  // (Fosc=48) 11719; 5859; 
 Dim prv As Byte

   pindex = pindex * 2                          // table offset value
   prv = pwmtbl(pindex)                         // get new PR2 value from array for frequency value
   FMaxDuty = (prv + 1) * 4                     // maximum duty cycle resolution based on PR2 value  
   PR2 = prv                                    // load PR2
   SetDuty1(0)                                  // output = 0V
   SetDuty2(0)                                  //
   T2CON = (T2CON And 252) Or pwmtbl(pindex+1)  // load prescaler value from array
End Sub

// initialise the module
FMaxDuty = 0
i would apreciate any suggestions.

thanks in advance

Richard
Hmmm..

Jerry Messina
Swordfish Developer
Posts: 1473
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Post by Jerry Messina » Tue Jul 05, 2011 1:30 pm

Richard -

Which compiler/version are you using?

The reason I ask is that many of the registers you're using are located in bank15 but are outside the access bank, so they require the use of bank select instructions.

richardb
Posts: 310
Joined: Tue Oct 03, 2006 8:54 pm

Post by richardb » Tue Jul 05, 2011 1:52 pm

Hi Jerry,

Ver 2.2.0.9 icc 1.1.5.5
Hmmm..

Jerry Messina
Swordfish Developer
Posts: 1473
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Post by Jerry Messina » Tue Jul 05, 2011 5:32 pm

From what I can tell, it would appear that the compiler may not be generating the correct code for those upper registers on the 66K80 family of parts. It doesn't seem to be getting the upper ACCESS bank correct.

Also, the device .bas file doesn't appear to be right, at least using the file SystemConvert generated from MPLAB 8.73/MPASM 5.42

Code: Select all

#const _ram_banks = $0F                // 15 RAM bank(s) used
#variable _maxaccess = $60             // access ram is 96 bytes
#variable _maxram = $0E80              // 3712 bytes of user RAM
That _maxram setting would include a number of the CAN registers from $0E41-$0E80.

richardb
Posts: 310
Joined: Tue Oct 03, 2006 8:54 pm

Post by richardb » Wed Jul 06, 2011 7:49 am

Thanks for the reply Jerry,


Unfortunately I don’t know enough pic assembly to get me out of this.


I was hoping to use this pic as it would be a good general purpose pic for me as it’s cheap
has lots of ram/ rom
has a 12 bit adc with differential inputs if needed and a 4.096V internal ref.
and runs at 64Mhz.


Can you point me in the right direction. or should this problem get fed back to david?
Hmmm..

User avatar
David Barker
Swordfish Developer
Posts: 1214
Joined: Tue Oct 03, 2006 7:01 pm
Location: Saltburn by the Sea, UK
Contact:

Post by David Barker » Wed Jul 06, 2011 8:19 am

I spoke with Jerry last night and I am currently testing a fix. I'll probably post as an online update, so keep checking...

richardb
Posts: 310
Joined: Tue Oct 03, 2006 8:54 pm

Post by richardb » Wed Jul 06, 2011 8:36 am

Thats good to hear.

Thanks
Hmmm..

User avatar
David Barker
Swordfish Developer
Posts: 1214
Joined: Tue Oct 03, 2006 7:01 pm
Location: Saltburn by the Sea, UK
Contact:

Post by David Barker » Wed Jul 06, 2011 10:48 am

There is an update available which should now fix this problem

http://www.sfcompiler.co.uk/forum/viewtopic.php?t=1510

richardb
Posts: 310
Joined: Tue Oct 03, 2006 8:54 pm

Post by richardb » Wed Jul 06, 2011 11:01 am

That works perfectly now! :)

Thanks again to Jerry and David.


on a side note:-

This pic is only supported with the Pickit3 :(
Hmmm..

User avatar
Senacharim
Posts: 139
Joined: Tue Aug 10, 2010 5:19 pm
Location: Ventura, CA

Post by Senacharim » Wed Jul 06, 2011 3:08 pm

richardb wrote:That works perfectly now! :)

Thanks again to Jerry and David.


on a side note:-

This pic is only supported with the Pickit3 :(
Are you sure about that?

I've been playing with K-Series PICs for awhile now, burning the code in using the melabs U2 usb programmer (not to sound like an advert... sry).

I *did* end up needing to make a slightly modified 10-pin connector (though the nice fellows at melabs offered to do so as well)

http://store.melabs.com/prod/u2/U2BUN.html

I only mention this 'cuz I'd looked at the PicKit3 and it's science-damned expensive! Anyhow, best of luck.
Surviving Member
Bermuda Triangle Battalion
from 2026 to 1992

Voted "Most likely to time travel"--Class of 2024.

richardb
Posts: 310
Joined: Tue Oct 03, 2006 8:54 pm

Post by richardb » Wed Jul 06, 2011 3:17 pm

ok another small problem, i cant seem to get the adc to work correctly.

upto half the supply the adc seems to work fine 2.5v =2048 counts
3v = 2750
3.5 = 2560
4 = 2420
4.5= 2400
also the values are much more erratic over 2.5 V

the voltage on the adc input looks stable no glitches and ther's a 100nf cap on it.

i've butchered the adc module

Code: Select all

{
*****************************************************************************
*  Name    : ADC.bas                                                        *
*  Author  : David John Barker                                              *
*  Notice  : Copyright (c) 2007 Mecanique                                   *
*          : All Rights Reserved                                            *
*  Date    : 12/01/2007                                                     *
*  Version : 1.0                                                            * 
*          : 1.1 Corrected bitnames for 18F1220, 18F1320 devices            *
*  Notes   :                                                                *
*          :                                                                *
*****************************************************************************
}
Module ADCK80
  
// conversion time constants...
Public Const
   FOSC_2  = %000,
   FOSC_4  = %100,
   FOSC_8  = %001,
   FOSC_16 = %101,
   FOSC_32 = %010,
   FOSC_64 = %110,
   FRC     = %011

// channel select constants...
Public Const
   AN0 = $00,
   AN1 = $01,
   AN2 = $02,
   AN3 = $03,
   AN4 = $04,
   AN5 = $05,
   AN6 = $06
   
#if _adc = 8
Public Const
   AN7 = $07
#elseif _adc = 12
Public Const
   AN8 = $08,
   AN9 = $09,
   AN10 = $0A,
   AN11 = $0B
#elseif _adc = 16
Public Const
   AN12 = $0C,
   AN13 = $0D,
   AN14 = $0E,
   AN15 = $0F
#endif   
            
Public Dim

   CHS4    As ADCON0.6,
   CHS3    As ADCON0.5,
   CHS2    As ADCON0.4,
   CHS1    As ADCON0.3,
   CHS0    As ADCON0.2,
   GO_DONE As ADCON0.1,
   ADON    As ADCON0.0,

   // ADCON1...
   TRIGSEL1 As ADCON1.7,
   TRIGSEL0 As ADCON1.6,
   VCFG1    As ADCON1.5,
   VCFG0    As ADCON1.4,
   VNCFG    As ADCON1.3,
   CHSN2    As ADCON1.2,
   CHSN1    As ADCON1.1,
   CHSN0    As ADCON1.0,  
   
   // ADCON2...
   ADFM As ADCON2.7,
   AQT2 As ADCON2.5,
   AQT1 As ADCON2.4,   
   AQT0 As ADCON2.3,
   ADCS2 As ADCON2.2,
   ADCS1 As ADCON2.1,
   ADCS0 As ADCON2.0, 

   // extended alias...
   Convert As ADCON0.Booleans(1),       // GO_DONE, POR = 0
   RightJustify As ADCON2.Booleans(7)   // ADFM, POR = false

// ADCON(x) extended alias...   
Public Dim
   Enabled As ADCON0.Booleans(0),       // ADON, POR = 0 
   ADResult As ADRESL.AsWord            // 16 bit ADC result          
{
****************************************************************************
* Name    : SetConvTime                                                    *
* Purpose : Set the conversion time. Valid parameters include FOSC_2,      *
*         : FOSC_4, FOSC_8, FOSC_16, FOSC_32, FOSC_64 and FRC              *
****************************************************************************
}
Public Sub SetConvTime(pValue As Byte)
   ADCS2 = pValue.2
   ADCS1 = pValue.1
   ADCS0 = pValue.0
End Sub 
{
****************************************************************************
* Name    : Read                                                           *
* Purpose : Read currently uses delayus for the acquistion time, which has *
*         : the following minimum overheads                                *
*         : 4Mhz - 24us                                                    *
*         : 8Mhz - 12us                                                    *
*         : 10Mhz - 8us                                                    *
*         : 16Mhz - 5us                                                    *
*         : 20Mhz plus - 2us                                               * 
*         : If your acquistion time requirements fall below the above,     *
*         : just create a copy of this function in your main program (or   *
*         : another module) and replace delayms(ATime) with a constant     *
****************************************************************************
}
Public Function Read(pChannel As Byte) As Word
   // set channel...
    CHS0 = pChannel.0
    CHS1 = pChannel.1
    CHS2 = pChannel.2
    CHS3 = pChannel.3
    CHS4 = pChannel.4
   // read ADC...
    
    Enabled = true  
    DelayUS(20)
    Convert = true  
    // wait for completion, then disable ADC...
    While Convert      
    Wend           
    Enabled = false   
    Result = ADResult
End Function


// defaults
RightJustify = true
any ideas ?
Hmmm..

Jerry Messina
Swordfish Developer
Posts: 1473
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Post by Jerry Messina » Wed Jul 06, 2011 5:32 pm

I've never used that chip or the adc at 64MHz, but it sounds like the adc timing may not be setup properly.

Are you calling 'SetConvTime(FOSC_64)' in your main code?

If so, perhaps try a slower clock and see what happens. There is some errata for the K80 adc that suggests it's only good for 10 bits. High offset, non-linear, lots of missing codes, etc.

Also, make sure it's set up for single-ended mode (bits ADCON1[2:0] = 0) unless you're using it differentially.

richardb
Posts: 310
Joined: Tue Oct 03, 2006 8:54 pm

Post by richardb » Thu Jul 07, 2011 7:19 am

@Senacharim

Sorry i meant it wasnt supported by the pickit2.
Hmmm..

richardb
Posts: 310
Joined: Tue Oct 03, 2006 8:54 pm

Post by richardb » Thu Jul 07, 2011 8:12 am

Hi Jerry,

I looked at the errata but it doesnt sound like the problem i was having.

I am calling SetConvTime(FOSC_64)

i did try turning off the PLL and it didnt seem to make muchdifference but i wasnt sure if it was using the xtal or the output of the PLL.


ok just tried that again it actually did improve matters


@5V input
@64MHz ~= 2550counts

@16MHz =3000counts

using RC osc for the adc SetConvTime(FRC)
= 3400 counts.


after all this ... noticed the aqisition time wasnt set in the adc module.

i've added this sub to the module and set it to%111

Public Sub SetAQTime(pValue As Byte)
AQT2 = pValue.2
AQT1 = pValue.1
AQT0 = pValue.0
End Sub


this works fine now even using SetConvTime(FOSC_64)
Hmmm..

Jerry Messina
Swordfish Developer
Posts: 1473
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Post by Jerry Messina » Thu Jul 07, 2011 11:11 am

I saw that, but totally misread that part of the datasheet!

Thanks for the heads up, Richard.

Post Reply