Show
Ignore:
Timestamp:
07/31/08 13:16:09 (5 months ago)
Author:
liamstask
Message:

- incorporating additions from #64
- can more easily configure PWM channels - timing, alignment, etc.
- more & better doc for PWM

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • firmware/trunk/core/makingthings/pwm.c

    r771 r774  
    1919  PWM - Pulse Width Modulation. 
    2020  Library of functions for the Make Application Board's PwmOut Subsystem. 
    21   //ToDo: DW choose which functions are public, and confirm/correct annotations 
    2221*/ 
    2322 
     
    5958} Pwm; 
    6059 
    61 /** \defgroup Pwm PWM 
    62   The Pwm subsystem provides control of the 4 PWM outputs on the SAM7X. 
    63   The Pwm subsystem of the Controller Board can be used independently from the PWM_Out subsystem 
    64   of the Application Board, and in fact the AppBoard PwmOut relies on the Controller Board PWM. 
     60/** \defgroup Pwm PWM (Pulse Width Modulation) 
     61  The PWM subsystem provides control of the 4 PWM outputs on the SAM7X. 
     62 
     63  The Make Controller has 4 PWM lines.  These can each be configured separately and can control 
     64  up to 2 output lines directly, the 2 lines running either parallel or inverted.  For a very simple 
     65  start, just see Pwm_Set( ) and Pwm_Get( ) as these will start driving your PWMs immediately with 
     66  very little hassle.   
     67 
     68  \section padjust Period adjustment of the PWM unit 
     69  Configuring and setting the clock for the PWM system can be quite a complicated matter.  Here are  
     70  some of the relevant issues. 
     71   
     72  Each of the 4 PWM channels is fed in a clock, as determined by its clock source: 
     73   - Clock source 0-10 represent the Master clock divided by 2 to the power of the Clock Source Value.  eg. a clock  
     74   source value of 5 = a clock rate of MasterClock/(2^5) 
     75   - A value of 11 sets the Clock source to be generated by clock Divider A (Default) 
     76   - A value of 12 sets the Clock source to be generated by clock Divider B 
     77   
     78  If either Clock Divider A or Clock Divider B is used, you can adjust their values individually to 
     79  allow the clock period to precisely match your needs.  Each clock divider has two values, a \b Mux value  
     80  and a \b Divider value.   
     81   
     82  The mux works just like the clock source values, and chooses Master clock divided by 2 to  
     83  the power of the Clock Source Value, eg. a DividerXMux value of 5 == a clock rate of MasterClock/(2^5). 
     84  The Divider value sets a linear divider, which is fed the clock value as selected by the Mux, and returns that  
     85  clock value divided by the divider value.  This output value is what is fed out of the divider unit.  A output  
     86  formula:  
     87  \code output = MCLK / ( (2^DividerMux) * DividerValue ) \endcode 
    6588   
    66   @see PWM_Out 
     89  The PWM subsystem of the Controller Board can be used independently from the \ref PwmOut  
     90  library, since the \ref PwmOut library relies on the core PWM. 
     91 
    6792  \ingroup Core 
    6893  @{ 
     
    99124  return Pwm.duty[ index ]; 
    100125} 
    101  
    102 /** @} 
    103 */ 
    104126 
    105127int Pwm_Start( int channel ) 
     
    243265  return io; 
    244266} 
     267 
     268/** 
     269  Adjust the clock period on Divider A. 
     270  See AT91SAM7X manual for more information p.421 
     271 
     272  Contributed by TheStigg - http://www.makingthings.com/author/thestigg 
     273  @param val An int between 0 and 4096. 
     274  @return 0 on success. 
     275*/ 
     276int Pwm_SetDividerA(int val) 
     277{  
     278  if( val < 0 || val > ( 1 << 12 ) ) 
     279    return CONTROLLER_ERROR_ILLEGAL_PARAMETER_VALUE; 
     280 
     281  // First disable PWM controller for all 4 channels. 
     282  AT91C_BASE_PWMC->PWMC_DIS = 0x0000000f; 
     283 
     284  // Now Set the new Clock values 
     285  AT91C_BASE_PWMC->PWMC_MR = (AT91C_BASE_PWMC->PWMC_MR & 0xffff0000) | val; 
     286 
     287  // Re-enable the active channels 
     288  AT91C_BASE_PWMC->PWMC_ENA = Pwm.channels; 
     289   
     290  return CONTROLLER_OK; 
     291} 
     292 
     293/** 
     294  Read the clock period on Divider A. 
     295 
     296  Contributed by TheStigg - http://www.makingthings.com/author/thestigg 
     297  @return The clock period on Divider A. 
     298*/ 
     299int Pwm_GetDividerA() 
     300{ 
     301  return (AT91C_BASE_PWMC->PWMC_MR & 0x0000ffff); 
     302} 
     303 
     304/** 
     305  Adjust the clock period on Divider B. 
     306  See AT91SAM7X manual for more information p.421 
     307 
     308  Contributed by TheStigg - http://www.makingthings.com/author/thestigg 
     309  @param val An int between 0 and 4096. 
     310  @return 0 on success. 
     311*/ 
     312int Pwm_SetDividerB(int val) 
     313{  
     314  if( val < 0 || val > ( 1 << 12 ) ) 
     315    return CONTROLLER_ERROR_ILLEGAL_PARAMETER_VALUE; 
     316 
     317  //New function which adjusts the clock period on Divider A. 
     318  //See AT91SAM7X manual for more information p.421 
     319 
     320  // First disable PWM controller for all 4 channels. 
     321  AT91C_BASE_PWMC->PWMC_DIS = 0x0000000f; 
     322 
     323  // Now Set the new Clock values 
     324  AT91C_BASE_PWMC->PWMC_MR = (AT91C_BASE_PWMC->PWMC_MR & 0x0000ffff) | ( val << 16 ); 
     325 
     326  // Re-enable the active channels 
     327  AT91C_BASE_PWMC->PWMC_ENA = Pwm.channels; 
     328   
     329  return CONTROLLER_OK; 
     330} 
     331 
     332/** 
     333  Read the clock period on Divider B. 
     334 
     335  Contributed by TheStigg - http://www.makingthings.com/author/thestigg 
     336  @return The clock period on Divider B. 
     337*/ 
     338int Pwm_GetDividerB() 
     339{ 
     340  return (AT91C_BASE_PWMC->PWMC_MR >> 16); 
     341} 
     342 
     343/** 
     344  Set the clock divider for a particular channel. 
     345  For values 0-10, the Master_Clock is divided by (2^val).  For example, 
     346  for 4 the resulting period will be Master Clock / 16, as 2 ^ 4 == 16. 
     347 
     348  When val is 11, Clock Divider A is used.  When val is 12, Clock Divider B 
     349  is used.  Values other than 0 - 12 are not valid. 
     350 
     351  Contributed by TheStigg - http://www.makingthings.com/author/thestigg 
     352  @param channel The PWM channel (0-3) you'd like to configure. 
     353  @param val The new clock divider. 
     354  @return 0 on success. 
     355*/ 
     356int Pwm_SetClockSource(int channel, int val) 
     357{ 
     358  if ( channel < 0 || channel > PWM_COUNT ) 
     359    return CONTROLLER_ERROR_ILLEGAL_INDEX; 
     360 
     361  if ( val < 0 || val > 12 ) 
     362    return CONTROLLER_ERROR_ILLEGAL_PARAMETER_VALUE; 
     363 
     364  AT91S_PWMC_CH *pwm = &AT91C_BASE_PWMC->PWMC_CH[ channel ]; 
     365  int c = 1 << channel; 
     366 
     367  // Disable the Channel 
     368  AT91C_BASE_PWMC->PWMC_DIS = c; 
     369 
     370  // Set the Channel Divider Value 
     371  pwm->PWMC_CMR = (pwm->PWMC_CMR & 0x00000700) | val; 
     372   
     373  // Re-enable the Channel 
     374  AT91C_BASE_PWMC->PWMC_ENA = c; 
     375 
     376  return CONTROLLER_OK; 
     377} 
     378 
     379/** 
     380  Read the clock source for a particular channel. 
     381  Contributed by TheStigg - http://www.makingthings.com/author/thestigg 
     382  @param channel The PWM channel (0-3) whose channel you'd like to read. 
     383  @return The clock source. 
     384  @see Pwm_SetClockSource( ) 
     385*/ 
     386int Pwm_GetClockSource(int channel) 
     387{ 
     388  if ( channel < 0 || channel > PWM_COUNT ) 
     389    return CONTROLLER_ERROR_ILLEGAL_INDEX; 
     390 
     391  return (AT91C_BASE_PWMC->PWMC_CH[ channel ].PWMC_CMR & 0x0000000f); 
     392} 
     393 
     394/** 
     395  Set the wave form properties of the PWM contoller for a given channel. 
     396  The waveform properties are controlled by bits 0, 1, and 2. 
     397   - bit 0 sets whether the PWModule is Left aligned (0) or Center aligned (1) 
     398   - bit 1 sets whether the PWMoudle's polarity starts out low (0) or high (1) 
     399   - bit 2 is not supported at this time. 
     400 
     401  Contributed by TheStigg - http://www.makingthings.com/author/thestigg 
     402  @param channel the PWM channel (0-3) that you want to configure 
     403  @param val The mask of values as described above. 
     404  @return 0 on success. 
     405*/ 
     406int Pwm_SetWaveformProperties(int channel, int val) 
     407{ 
     408  if ( channel < 0 || channel > PWM_COUNT ) 
     409    return CONTROLLER_ERROR_ILLEGAL_INDEX; 
     410 
     411  if ( val < 0 || val > 3 ) 
     412    return CONTROLLER_ERROR_ILLEGAL_PARAMETER_VALUE; 
     413 
     414  AT91S_PWMC_CH *pwm = &AT91C_BASE_PWMC->PWMC_CH[ channel ]; 
     415  int c = 1 << channel; 
     416 
     417  // Disable the Channel 
     418  AT91C_BASE_PWMC->PWMC_DIS = c; 
     419 
     420  // Set the Channel Divider Value 
     421  pwm->PWMC_CMR = (pwm->PWMC_CMR & 0x0000040f) | ( val << 8 ); 
     422   
     423  // Re-enable the Channel 
     424  AT91C_BASE_PWMC->PWMC_ENA = c; 
     425 
     426  return CONTROLLER_OK; 
     427} 
     428 
     429/** 
     430  Read the waveform configuration of a specified PWM channel 
     431 
     432  Contributed by TheStigg - http://www.makingthings.com/author/thestigg 
     433  @param channel The PWM channel (0-3) to read from. 
     434  @return A bitmask describing the waveform configuration. 
     435  @see Pwm_SetWaveformProperties( ) 
     436*/ 
     437int Pwm_GetWaveformProperties(int channel) 
     438{ 
     439  if ( channel < 0 || channel > PWM_COUNT ) 
     440    return CONTROLLER_ERROR_ILLEGAL_INDEX; 
     441   
     442  return ( (AT91C_BASE_PWMC->PWMC_CH[ channel ].PWMC_CMR >> 8) & 0x00000003 ); 
     443} 
     444 
     445/** @} 
     446*/