Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.
|
Forum Index : Microcontroller and PC projects : Maximite PWM
Author | Message | ||||
seco61 Senior Member Joined: 15/06/2011 Location: AustraliaPosts: 205 |
Hi All. I have modified the Maximite firmware to provide a PWM capability. The PWM output is available on logical pins 7 - 10. The base PWM frequency can be from 1Hz to 5000Hz. The duty time can be set from 0% to 100%. However, at frequencies above 500Hz the duty time percentage will be rounded (eg at 1000Hz the increments are at 2% and at 5000Hz the increments are 10%). To set a pin to PWM mode, you use the SETPIN command. The format is: SETPIN pin,cfg,frequency,pwm where pin is 7 - 10 cfg is 10 for PWM mode frequency is 1 - 5000 (for 1Hz to 5000Hz) pwm is 0 - 100 (for 0% to 100% duty time) To modify the duty time just issue the SETPIN command again with a different duty time percentage. An example command: SETPIN 7,10,500,25 -> set pin 7 to PWM with a frequency of 500Hz and a duty time of 25% SETPIN 7,10,500,50 -> change the duty time to 50% As this firmware uses the timer in the keyboard routine, I have incorporated Jim's (Jimbo) updated keyboard scan code routine (see Keyboard function key mappings post). Firmware download: Maximite.hex Please try and report any issues. Regards Gerard (vk3cg/vk3grs) Regards Gerard (vk3cg/vk3grs) |
||||
Gizmo Admin Group Joined: 05/06/2004 Location: AustraliaPosts: 5078 |
Hi Gerard Good work! Quick question for those wondering, does the PWM output run independently from normal program operation, ie, is it running in the background. And will any other commands affect it, or will it affect any commands? With I2C and PWM, the Maximite is turning into one versatile little beastie Glenn The best time to plant a tree was twenty years ago, the second best time is right now. JAQ |
||||
seco61 Senior Member Joined: 15/06/2011 Location: AustraliaPosts: 205 |
Hi Glenn. The PWM output runs in the background. It should have no impact on any running program - though as there are a couple of extra lines of C code in the timer interrupt routine the MMBAsic interpreter throughput may drop slightly. All 4 PWM pins can be running simultaneously, at different frequencies and duty times. Regards Gerard (vk3cg/vk3grs) Regards Gerard (vk3cg/vk3grs) |
||||
Gizmo Admin Group Joined: 05/06/2004 Location: AustraliaPosts: 5078 |
Its a work of art Gerard! I connected a LED and 330ohm in series to pin 8, then ran the following. 10 for i=1 to 100 20 setpin 8,10,2000,i 30 pause 100 40 next And the LED progressively got brighter over a few seconds. Glenn The best time to plant a tree was twenty years ago, the second best time is right now. JAQ |
||||
Gizmo Admin Group Joined: 05/06/2004 Location: AustraliaPosts: 5078 |
Did some more testing this morning and have noticed a problem. There is a bit of video flicker, especially once a PWM command has been issued. Random lines seam to jump sideways by several pixels. I think Geoff has come across this before, something to do with timings. Glenn The best time to plant a tree was twenty years ago, the second best time is right now. JAQ |
||||
Dave Everett Regular Member Joined: 24/06/2011 Location: AustraliaPosts: 43 |
Gerard, I've been looking at doing this as well, however I want to use the onboard PWM. There are 2 of the 4 PWM pins available, and this way the frequency can be much higher. I need something between 20 and 32khz. This would mean modifiying the PCB, I intend to reuse 2 of the 3 ground lines on the 26 way to take the PWM output pins. Dave |
||||
bigmik Guru Joined: 20/06/2011 Location: AustraliaPosts: 2914 |
Love it, Thanks Gerard, Just a question that will probably show how dumb I am but at I assume that a 50% setting means a `proper' square wave ie. high 50% (presume 3.3v) and low 50%. does that mean then that 100% is Always on? Regards, Mick Mick's uMite Stuff can be found >>> HERE (Kindly hosted by Dontronics) <<< |
||||
haiqu Senior Member Joined: 30/07/2011 Location: AustraliaPosts: 152 |
Mick, Correct! Rob unzip, strip, touch, finger, grep, mount, fsck, more, yes, fsck, fsck, fsck, umount, sleep |
||||
seco61 Senior Member Joined: 15/06/2011 Location: AustraliaPosts: 205 |
Hi Dave. I have also looked at this, but it would probably have to be a custom implementation as it involves modifying the base Maximite and soldering directly to a MCU pin. Whilst I have done this quite a few times, it will not be an option for many - hence the current implementation. Having said that, the overhead of adding a custom command to use the OC1 pin as a PWM output would be slight and as it would not interfere with anything else I may as well code it and then run it by Geoff to see if he is happy to have it as an "optional" command (similar to I2C in an appendix!). Either way I will have a go and post the modified code soon. As timer 3 is used by the video subsystem, this only leaves timer 2 for the PWM modules. So if you were to use both OC1 and OC4, they would have to run at the same frequency. I would also love to have a RS232 capability using the onboard peripherals. I know Geoff is going to be coding a "bit banging" solution (at least I think that is the case) as the UART peripheral pins are not available at the I/O connector. However, for those who are able to solder directly to the MCU pins, pins 21 and 51 could be used to provide the Rx and Tx capability respectively. Regards Gerard (vk3cg/vk3grs) Regards Gerard (vk3cg/vk3grs) |
||||
seco61 Senior Member Joined: 15/06/2011 Location: AustraliaPosts: 205 |
Hi Dave. Here is my version of a PWM command that uses the OC1 output (pin 46). The firmware is the current v2.5 with my earlier PWM, Jim's keyboard scan update and the new "external" PWM command: Maximite.hex For the time being I have placed the external PWM code into Custom.c and Custom.h (see below). The new command is: PWM freq,duty where freq is 5 - 800000 (5Hz to 800kHz) or 0 to disable duty is 0 - 100 for 0% to 100% duty cycle Custom.c /*********************************************************** ************************************************************ MMBasic custom.c Handles all the custom commands and functions in MMBasic. These are commands and functions that are not normally part of the core BASIC language. This is a good place to insert your own customised commands. Copyright 2011 Geoff Graham - http://geoffg.net This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. ************************************************************ ************************************************************ / #include <p32xxxx.h> // device specific defines #include <plib.h> // peripheral libraries #define INCLUDE_FUNCTION_DEFINES #include "Maximite.h" #include "MMBasic.h" #include "Operators.h" #include "Commands.h" #include "External.h" #include "Misc.h" #include "Files.h" #include "Custom.h" /*********************************************************** ************************************************************ ********************* custom commands and functions each function is responsible for decoding a command all function names are in the form cmd_xxxx() (for a basic command) or fun_xxxx() (for a basic function) so, if you want to search for the function responsible for the NAME command look for cmd_name There are 4 items of information that are setup before the command is run. All these are globals. int cmdtoken This is the token number of the command (some commands can handle multiple statement types and this helps them differentiate) char *cmdline This is the command line terminated with a zero char and trimmed of leading spaces. It may exist anywhere in memory (or even ROM). char *nextstmt This is a pointer to the next statement to be executed. The only thing a command can do with it is save it or change it to some other location. int CurrentLineNbr This is read only and is set to zero if the command is in immediate mode. The only actions a command can do to change the program flow is to change nextstmt or execute longjmp(mark, 1) if it wants to abort the program. ******************** ************************************************************ ************************************************************ / void cmd_pwm(void) { static unsigned int pwm_enabled, pwm_freq; unsigned int freq, pwm; getargs(&cmdline, 3, ","); if (argc != 3) error("Invalid syntax"); freq = getinteger(argv[0]); if (freq == 0) { OC1CONCLR = 0x0000ffff; // Disable the output compare module T2CONCLR = 0x0000ffff; // Disable timer 2 module pwm_enabled = 0; pwm_freq = 0; return; } if (freq < 5 || freq > 800000) error("Invalid frequency (must be 5 - 800000, or 0 to disable)"); pwm = getinteger(argv[2]); if (pwm < 0 || pwm > 100) error("Invalid PWM (must be 0 - 100)"); if (!pwm_enabled || pwm_freq != freq) { pwm_enabled = 0; pwm_freq = freq; // Save current frequency OC1CONCLR = 0x0000ffff; // Disable the output compare module T2CONCLR = 0x0000ffff; // Disable timer 2 module if (freq >= 1280) {} else if (freq >= 640) {freq <<= 1; T2CONSET = 0x00000010;} else if (freq >= 320) {freq <<= 2; T2CONSET = 0x00000020;} else if (freq >= 160) {freq <<= 3; T2CONSET = 0x00000030;} else if (freq >= 80) {freq <<= 4; T2CONSET = 0x00000040;} else if (freq >= 40) {freq <<= 5; T2CONSET = 0x00000050;} else if (freq >= 20) {freq <<= 6; T2CONSET = 0x00000060;} else {freq <<= 8; T2CONSET = 0x00000070;} TMR2 = 0; // Clear timer 2 counter PR2 = ((BUSFREQ + (freq >> 1)) / freq) - 1; // Set timer 2 period } OC1RS = ((pwm * (PR2 + 1)) + 50) / 100; // Set duty period if (!pwm_enabled) { pwm_enabled = 1; OC1R = OC1RS; // Set initial duty period OC1CON = 0x00000006; // Enable PWM mode OC1CONSET = 0x00008000; // Enable output compare module T2CONSET = 0x00008000; // Enable timer 2 } } Custom.h /*********************************************************** ************************************************************ MMBasic custom.h Include file that contains the globals and defines for custom.c in MMBasic. Copyright 2011 Geoff Graham - http://geoffg.net This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. ************************************************************ ************************************************************ / /*********************************************************** *********************** All command tokens tokens (eg, PRINT, FOR, etc) should be inserted in this table ************************************************************ **********************/ #ifdef INCLUDE_COMMAND_TABLE // the format is: // TEXT TYPE P FUNCTION TO CALL // where type is always T_CMD // and P is the precedence (which is only used for operators and not commands) { "PWM", T_CMD, 0, cmd_pwm }, #endif /*********************************************************** *********************** All other tokens (keywords, functions, operators) should be inserted in this table ************************************************************ **********************/ #ifdef INCLUDE_TOKEN_TABLE // the format is: // TEXT TYPE P FUNCTION TO CALL // where type is T_NA, T_FUN, T_FNA or T_OPER argumented by the types T_STR and/or T_NBR // and P is the precedence (which is only used for operators) #endif /*********************************************************** *********************** the C language function associated with commands, functions or operators should be declared here Also general definitions used by other modules ************************************************************ **********************/ #ifdef INCLUDE_FUNCTION_DEFINES #ifndef CUSTOM_HEADER #define CUSTOM_HEADER // format: // void cmd_???(void) // void fun_???(void) // void op_???(void) void cmd_pwm(void); #endif #endif Regards Gerard (vk3cg/vk3grs) Regards Gerard (vk3cg/vk3grs) |
||||
Dave Everett Regular Member Joined: 24/06/2011 Location: AustraliaPosts: 43 |
Yes that's right mate. I don't think it's a major issue. Certainly for the applications I'm thinking of (robotics) as both drive motors would be running at the same frequency anyway. I appreciate the work you are doing. Dave |
||||
Dave Everett Regular Member Joined: 24/06/2011 Location: AustraliaPosts: 43 |
Fantastic Gerard, I hadn't put much thought into how the command would work, but the way you've handled it would also make it easy to add OC4 as another argument. I'll get a chance to play with your hex file over the weekend, thanks mate. Dave |
||||
seco61 Senior Member Joined: 15/06/2011 Location: AustraliaPosts: 205 |
Hi Dave. I modified the code to take an extra parameter: PWM module,freq,pwm where module is 1 or 4 (1 - OC1 on pin 46, 4 - OC4 on pin 51) freq is 5 - 800000 (5Hz to 800kHz) or 0 to disable the module pwm is 0 - 100 (for 0% to 100% duty cycle) The firmware has been updated: Maximite.hex The modified Custom.c /*********************************************************** ************************************************************ MMBasic custom.c Handles all the custom commands and functions in MMBasic. These are commands and functions that are not normally part of the core BASIC language. This is a good place to insert your own customised commands. Copyright 2011 Geoff Graham - http://geoffg.net This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. ************************************************************ ************************************************************ / #include <p32xxxx.h> // device specific defines #include <plib.h> // peripheral libraries #define INCLUDE_FUNCTION_DEFINES #include "Maximite.h" #include "MMBasic.h" #include "Operators.h" #include "Commands.h" #include "External.h" #include "Misc.h" #include "Files.h" #include "Custom.h" /*********************************************************** ************************************************************ ********************* custom commands and functions each function is responsible for decoding a command all function names are in the form cmd_xxxx() (for a basic command) or fun_xxxx() (for a basic function) so, if you want to search for the function responsible for the NAME command look for cmd_name There are 4 items of information that are setup before the command is run. All these are globals. int cmdtoken This is the token number of the command (some commands can handle multiple statement types and this helps them differentiate) char *cmdline This is the command line terminated with a zero char and trimmed of leading spaces. It may exist anywhere in memory (or even ROM). char *nextstmt This is a pointer to the next statement to be executed. The only thing a command can do with it is save it or change it to some other location. int CurrentLineNbr This is read only and is set to zero if the command is in immediate mode. The only actions a command can do to change the program flow is to change nextstmt or execute longjmp(mark, 1) if it wants to abort the program. ******************** ************************************************************ ************************************************************ / static unsigned int pwm_enabled, pwm_freq; void cmd_pwm(void) { unsigned int module, freq, pwm; getargs(&cmdline, 5, ","); if (argc != 5) error("Invalid syntax"); module = getinteger(argv[0]); if (module != 1 && module != 4) error("Output Compare module must be 1 or 4"); freq = getinteger(argv[2]); if (freq == 0) { if (module == 1) OC1CONCLR = 0x0000ffff; // Disable output compare module 1 else OC4CONCLR = 0x0000ffff; // Disable output compare module 4 pwm_enabled &= ~module; if (!pwm_enabled) { pwm_freq = 0; // Clear saved frequency T2CONCLR = 0x0000ffff; // Disable timer 2 module } return; } if (freq < 5 || freq > 800000) error("Invalid frequency (must be 5 - 800000, or 0 to disable)"); pwm = getinteger(argv[4]); if (pwm < 0 || pwm > 100) error("Invalid PWM (must be 0 - 100)"); if (pwm_freq != freq) { if (pwm_enabled & ~module) error("Cannot change frequency when other PWM output is enabled"); pwm_enabled = 0; // Clear status byte pwm_freq = freq; // Save current frequency OC1CONCLR = 0x0000ffff; // Disable output compare module 1 OC4CONCLR = 0x0000ffff; // Disable output compare module 4 T2CONCLR = 0x0000ffff; // Disable timer 2 module if (freq >= 1280) {} else if (freq >= 640) {freq <<= 1; T2CONSET = 0x00000010;} else if (freq >= 320) {freq <<= 2; T2CONSET = 0x00000020;} else if (freq >= 160) {freq <<= 3; T2CONSET = 0x00000030;} else if (freq >= 80) {freq <<= 4; T2CONSET = 0x00000040;} else if (freq >= 40) {freq <<= 5; T2CONSET = 0x00000050;} else if (freq >= 20) {freq <<= 6; T2CONSET = 0x00000060;} else {freq <<= 8; T2CONSET = 0x00000070;} TMR2 = 0; // Clear timer 2 counter PR2 = ((BUSFREQ + (freq >> 1)) / freq) - 1; // Set timer 2 period } if (module == 1) OC1RS = ((pwm * (PR2 + 1)) + 50) / 100; // Set duty period for output compare module 1 else OC4RS = ((pwm * (PR2 + 1)) + 50) / 100; // Set duty period for output compare module 4 if (!(pwm_enabled & module)) { pwm_enabled |= module; if (module == 1) { OC1R = OC1RS; // Set initial duty period for output compare module 1 OC1CON = 0x00000006; // Enable PWM mode on output compare module 1 OC1CONSET = 0x00008000; // Enable output compare module 1 } else { OC4R = OC1RS; // Set initial duty period for output compare module 4 OC4CON = 0x00000006; // Enable PWM mode on output compare module 4 OC4CONSET = 0x00008000; // Enable output compare module 4 } if (pwm_enabled == module) T2CONSET = 0x00008000; // Enable timer 2 } } void pwm_disable() { pwm_enabled = 0; // Clear status bits pwm_freq = 0; // Clear current frequency OC1CONCLR = 0x0000ffff; // Disable output compare module 1 OC4CONCLR = 0x0000ffff; // Disable output compare module 4 T2CONCLR = 0x0000ffff; // Disable timer 2 module } Custom.h was also modified to add the declaration for pwm_disable. The pwm_disable function is called from the ClearExternalIO function to disable the PWM module when the running MMBasic program ends. Regards Gerard (vk3cg/vk3grs) Regards Gerard (vk3cg/vk3grs) |
||||
Blackened Regular Member Joined: 11/08/2012 Location: AustraliaPosts: 66 |
Hey Gerard This is an old thread so I'm not expecting much, but I thought I'd ask. I have a Duinomite Mega and I was hoping to achieve something like what you have done. I only need a single PWM output pin. How hard would it be for me to incorporate your work into the DM 3.2C firmware? I'm completely clueless about this at the moment. I'm not sure if I'll spend the time to learn what I need to learn, or just use an external circuit on the audio out jack to switch from speaker to PWM out with amplification. A software solution would be my preference though. I don't suppose anyone has already done this? Grasping at straws here I know Cheers Peter |
||||
Print this page |