younder
Newbie
Offline
Posts: 11
Thank You
-Given: 26
-Receive: 7
|
|
« on: September 26, 2015, 07:15:46 19:15 » |
|
Hi Everyone! I've been testing the DSPic30F4012 on a trip computer for my 4WD for a while. I could not use HW PWM due to EXT_INT0, 1 & 2 (are being used by RPM, Speed and fuel flow meter). So I decided to study software PWM. Yes, I know it may not be a good idea for high frequencies like i.e. > 100Hz, however, I decided to test it and measure the cpu cycle time to compare the performance @ different frequencies. Below is the test code, with software PWM by Ttelmah & PCM_Programmer. The point is that, even with my full code, It did not show the CPU to be overloaded when I increase the timer 3 frequency from 1Khz to 4Khz or even more. Is it because of the 30MIPS? Or at this rate it shouldn't affect anyway? Longest cpu cycle time Software PWM @ 66Hz (Timer 3 Period = 500uSec): 0,005277s Longest cpu cycle time Software PWM @ 133Hz (Timer 3 Period = 250uSec): 0,005294s CCS Version: 5.049 Any comments would be appreciated!! Hugo Custom_Fct.h unsigned int i,Temp0; // ============================================================= // "Timer1 ISR", -> called every 568,888mSec <- // ============================================================= Unsigned int1 Cycle_Time_Overflow=0; Unsigned int16 Cycle_Time=0,Cycle_Time_Mem[2]={0,0}; Unsigned int32 Cycle_Time_Total=0,Cycle_Time_Max=0; #INT_TIMER1 void timer1() { Cycle_Time++; Cycle_Time_Overflow=1; } // ************************************************************* // ============================================================= // "Timer2 ISR", -> called every 25ms <- // 117,964,800 as the oscillator internal (Tosc) rate. // Divide by 4 to get the timer increment rate (Tclk), so 29,491,200 Hz. // Divide by 64 since the divide by 64 pre-scaler was set, so 460,800 counts / sec on the timer. // The timer is set to 54,015 (65,536-11,520), so it will overflow after 11,520 counts. // (1/460,800)*11,520=0,025s or 25ms. // set_timer2(54,015 + get_timer2()) Timer2 will overflow every 25ms... // ============================================================= union pulse_data_type { int8 buffer; int1 clock[8]; struct { int1 _25; int1 _50; int1 _100; int1 _200; int1 _500; int1 _1000; } mSec; }; union pulse_data_type pulse=0;
#INT_TIMER2 void timer2() { static int8 counter_SP[6] = {1,2,4,8,20,40}; //Counters Setpoint (Value*25ms) static int8 i, counter[6] = {1,2,3,4,5,6}, mask;
// set_timer2(54015 + get_timer2()); //11520counts = 25mSec mask=1; for (i=0;i<6;i++) { counter[i]--; if (counter[i]==0) { counter[i]=counter_SP[i]; pulse.buffer^=mask; } mask*=2; } } // ************************************************************* // ============================================================= // Rising/Falling edge pulses // ============================================================= union edge_data_type { int1 buffer[8]; struct { int1 _25; int1 _50; int1 _100; int1 _200; int1 _500; int1 _1000; } mSec; }; union edge_data_type R_Edge={0,0,0,0,0,0,0,0};
typedef struct Edge_scan { int1 scan[8]; }; union edge_scan_type { struct Edge_scan Buffer[6]; struct { int1 _25_scan[8]; int1 _50_scan[8]; int1 _100_scan[8]; int1 _200_scan[8]; int1 _500_scan[8]; int1 _1000_scan[8]; } mSec; }; union edge_scan_type Edge={0,0,0,0,0,0}; void Edge_Pulses() { static int1 aux_R[6]; //Auxiliar Variable static int8 Scan_Count[6]={0,0,0,0,0,0};
for (i=0;i<6;i++) { //Rising edge if (pulse.clock[i]) { //If pulse is true if (aux_R[i]==0) R_Edge.buffer[i]=1; else R_Edge.buffer[i]=0; //and aux is false then edge=TRUE for only one scan aux_R[i]=1; //Next scan edge pulse will be false } else aux_R[i]=0,R_Edge.buffer[i]=0; //Clear aux till next rising edge detection
//Edge array bits if (Edge.Buffer[i].scan[Scan_Count[i]]) { if (Scan_Count[i]<7) Edge.Buffer[i].scan[Scan_Count[i]+1]=1; Edge.Buffer[i].scan[Scan_Count[i]]=0; Scan_Count[i]++; if (Scan_Count[i]>7) Scan_Count[i]=0; } if (R_Edge.buffer[i] && (Scan_Count[i]==0)) Edge.Buffer[i].scan[0]=1; } }
// *************************************************************
// ============================================================= // A/D Function // ============================================================= Long Read_AD(int Channel) { Static Long Analog_Value; Switch(Channel) { case 0 : input(BAT_VOLTAGE), setup_adc_ports(sAN0, VSS_VDD); break; case 1 : input(ALTERNATOR_CURRENT), setup_adc_ports(sAN0 | sAN1, VSS_VDD); break; case 2 : input(FUEL_TANK_LEVEL), setup_adc_ports(sAN0 | sAN1 | sAN2, VSS_VDD); break; case 3 : input(COOLANT_TEMP), setup_adc_ports(sAN0 | sAN1 | sAN2 | sAN3, VSS_VDD); break; case 4 : input(AIR_TEMP), setup_adc_ports(sAN0 | sAN1 | sAN2 | sAN3 | sAN4, VSS_VDD); break; default: return(0); } set_adc_channel(channel); Analog_Value = read_adc(); setup_adc_ports(NO_ANALOGS); return(Analog_Value); } // *************************************************************
Test.c #include <30F4012.h> #device ADC=10 #fuses FRC_PLL16,NOPROTECT,NOWRT,MCLR,BORRES,PUT64,NOCKSFSM,BORV27,NODEBUG,NOWDT #use delay(Internal=117964800) // Internal 7.3728Mhz * FRC_PLL16 = 117964800Hz (30MIPS) #use i2c(MASTER, SCL=PIN_F3, SDA=PIN_F2, FAST, stream=I2C_SOFTWARE) #build (stack=256) // 128,256,384 or 512 depending how big the code is
//PORT B #define BAT_VOLTAGE PIN_B0 //AD0 - 12V battery level #define ALTERNATOR_CURRENT PIN_B1 //AD1 - Alternator´s current #define FUEL_TANK_LEVEL PIN_B2 //AD2 - Fuel tank level #define COOLANT_TEMP PIN_B3 //AD3 - Coolant Temperature #define AIR_TEMP PIN_B4 //AD4 - Internal Air Temperature #define KEY_BIT_1 PIN_B5 //IN - Key Bit 01
//PORT C #define KEY_BIT_2 PIN_C13 //IN - Key Bit 02 #define KEY_BIT_3 PIN_C14 //IN - Key Bit 03 #define LED_OUT PIN_C15 //OUT - LED
//PORT D #define GAS_FLOW_IN PIN_D0 //INT1 - Gasoline Flow Pulse #define SPEED_IN PIN_D1 //INT2 - Speed Sensor pulse
//PORT E #define AUX_01_OUT PIN_E0 //OUT - Auxiliar Output 1 (PWM 1) #define AUX_02_OUT PIN_E1 //OUT - Auxiliar Output 2 (PWM 2) #define RELAY_01_OUT PIN_E2 //OUT - Relay #01 #define RELAY_02_OUT PIN_E3 //OUT - Relay #02 #define AUX_01_IN PIN_E4 //IN - Auxiliar Input 1 #define AUX_02_IN PIN_E5 //IN - Auxiliar Input 2 #define RPM_IN PIN_E8 //INT0 - Tachometer Pulse #use FIXED_IO( E_outputs=PIN_E0,PIN_E1,PIN_E2,PIN_E3 )
#include <lib\i2c_Flex_LCD.h> #include <lib\Custom_Fct.h>
#define PWM_PIN PIN_E2 #define PWM_PIN2 PIN_E3 #define LOOPCNT 29
// ============================================================= // Global variables declaration // ============================================================= Unsigned int16 ADC_0=0,ADC_1=0,ADC_2=0,ADC_3=0,ADC_4=0,Key; Unsigned int8 width, width2; int1 first_scan_bit=1,Edge_new_screen=1,UP_Key, DOWN_Key, ENTER_Key;
#int_timer3 void timer3_isr(void) { static int8 loop = LOOPCNT; static int8 pulse,pulse2;
if(--loop == 0) { loop = LOOPCNT; pulse = width; pulse2 = width2; }
if(pulse) output_high(PWM_PIN), pulse--; else output_low(PWM_PIN); if(pulse2) output_high(PWM_PIN2), pulse2--; else output_low(PWM_PIN2); }
void Initialization() { //Disable all interrupts disable_interrupts(INTR_GLOBAL); // Initialize 20x4 LCD Display lcd_init(); //Configures Timer1 setup_timer1 (TMR_INTERNAL | TMR_DIV_BY_256, 65535); //Configures timer1 to overflow every 568,888mSec enable_interrupts(INT_TIMER1); //Configures Timer2 setup_timer2 (TMR_INTERNAL | TMR_DIV_BY_64, 11520); //Configures timer2 to overflow every 25mSec enable_interrupts(INT_TIMER2); //Configures Timer3 setup_timer3 (TMR_INTERNAL | TMR_DIV_BY_1, 7500); //7500counts = 250uSec enable_interrupts(INT_TIMER3); //ADC clock setup_adc(ADC_CLOCK_DIV_64 | ADC_TAD_MUL_8); //Set GIE&PEIE bits and Enable all interrupts enable_interrupts(INTR_GLOBAL); }
void LCD_Display_Diag() { if (Edge.mSec._50_scan[0]) { lcd_gotoxy(1, 1); printf(LCD_PUTC,"Actual Cycle:"); lcd_gotoxy(1, 2); printf(LCD_PUTC,"%1.6lws",Cycle_Time_Total/100); } if (Edge.mSec._100_scan[1]) { lcd_gotoxy(1, 3); printf(LCD_PUTC,"Longest Cycle:"); lcd_gotoxy(1, 4); printf(LCD_PUTC,"%1.6lws",Cycle_Time_Max/100); } }
long KeyScan() { static long inKey=0, key_mem=0; #bit inKey_bit0 = inKey.0 #bit inKey_bit1 = inKey.1 #bit inKey_bit2 = inKey.2
If (input(KEY_BIT_1)) { if (!UP_Key) delay_ms(20); //debouncing time UP_Key=1; inKey_bit0=1; } else UP_Key=0,inKey_bit0=0; If (input(KEY_BIT_2)) { if (!DOWN_Key) delay_ms(20); //debouncing time DOWN_Key=1; inKey_bit1=1; } else DOWN_Key=0,inKey_bit1=0; If (input(KEY_BIT_3)) { if (!ENTER_Key) delay_ms(20); //debouncing time ENTER_Key=1; inKey_bit2=1; } else ENTER_Key=0,inKey_bit2=0; if(inKey != key_mem){ key_mem=inKey; return inKey; } else return 0; }
void PWM() { static int8 cnt=0, cnt2=0; static int1 dup=1, ddown=1; //PWM 1 If (Edge.mSec._25_scan[1]) { if (dup) cnt++; else cnt--; if (cnt>29) dup=0; if (cnt==0) dup=1; width = cnt; }
//PWM 2 If (Edge.mSec._50_scan[2]) { if (ddown) cnt2++; else cnt2--; if (cnt2>29) ddown=0; if (cnt2==0) ddown=1; width2 = cnt2; } }
void AD() { static int8 Read_Analog=0;
Read_Analog++; if (Read_Analog>4)Read_Analog=0; Switch(Read_Analog) { case 0 : { ADC_0=Read_AD(0); } break; case 1 : { ADC_1=Read_AD(1); } break; case 2 : { ADC_2=Read_AD(2); } break; case 3 : { ADC_3=Read_AD(3); } break; case 4 : { ADC_4=Read_AD(4); } break; } }
void Cycle_time_measuring() { static int1 Flag_ResetCycleTime=0; static int8 Reset_Cycle_Time=0; static unsigned int16 Cycle_Time_Buffer=0;
Cycle_Time_Buffer=Cycle_Time; Cycle_Time_Mem[0]=get_timer1(); //get actual tmr1 value if ((Cycle_Time_Mem[0]==65535) && Cycle_Time_Overflow) Cycle_Time_Mem[0]=0,Cycle_Time_Overflow=0; if (Cycle_Time_Mem[0]>Cycle_Time_Mem[1]) { Temp0=Cycle_Time_Mem[0]-Cycle_Time_Mem[1]; //how many tmr1 counts since last measuring? Cycle_Time_Total=((((int32)Cycle_Time_Buffer*65535)+Temp0)*868); } else { if (Cycle_Time_Buffer<=0) Temp0=1; else Temp0=Cycle_Time_Buffer; Cycle_Time_Total=((((int32)Temp0*65535)-Cycle_Time_Mem[1]+Cycle_Time_Mem[0])*868); } Cycle_Time_Mem[1]=Cycle_Time_Mem[0]; //memorizes current tmr1 value in case a new interrupt happens before tmr1 overflows Cycle_Time=0; //Reset Actual Cycle time counter
if (Cycle_Time_Total>Cycle_Time_Max) Cycle_Time_Max=Cycle_Time_Total; //Reset Longest Cycle Time
If (ENTER_Key) Flag_ResetCycleTime=1; If (!ENTER_Key && Flag_ResetCycleTime && R_Edge.mSec._50) Reset_Cycle_Time++; if (Reset_Cycle_Time>=10) { Flag_ResetCycleTime=0; Reset_Cycle_Time=0; Cycle_Time_Max=0; } }
void Main() { Initialization(); while(1){ Edge_Pulses(); //Edge pulses pulses for general use Key=keyScan(); //Up, Down and Enter Keys Cycle_time_measuring(); //At this point, measure actual and longest cycle time AD(); //Just read AD ports PWM(); //Perform a Software 4Khz PWM (Timer 3 @ 250uSec) LCD_Display_Diag(); //Display measured values } } //------------------ EOF ---------------------
|