Hello,
The company where i presently work has given me an assignment with several constraints.
1)We have a legacy design whose black-box inputs and outputs must remain the same
(This is essential as we have about 3000 such machines on the field)
The design is that of a three phase waveform generator card with all the three phase sinewave references and a zero crossing (high low) as outputs(apart from other IO signals)
My job is to come up with the 3 phase waveform generator and the ZCD outputs.
2) The penultimate stage to the three phase waveform outputs should be three DAC0808
My design should drive the three DACs directly.
The previous design used a 40 pin PIC16F877A driving the DACS directly.
Due to firmware issues we have to redo the 3 phase section and I have been given the responsibility.
The engineer who worked on the earlier design has left the company and code documentation is non-existant for the older version.
I should NOT use the older PIC16F877A card due to hardware limitations on the older rev board.
I have come up with a 16F676 clocked at 20 Mhz driving three cascaded 595 to drive the DAC inputs.
This is the basic idea :-
Calculate the values to send to the dac,
send it to the 595,
latch it in the ISR so that the data is latched for all the three ports simultaneously.
and when the look up index values wraps around to zero toggle the zero crossing high low bit.
Here is the code i have come up with
(I am unable to paste the code here so i am just attaching it.)
As a first step i have attached three leds to the RC3, RC4, RC5 i.e the zero crossing indicator pins with external current limiting resistors.
But the leds behave erratically.
I expect to see all the leds on with equal intensity,
but only RC4 led blinks with highest intensity and RC3 is VERY dim and RC5 does not light up at all.
Probing the MCU signals with a Open logic sniffer i saw that the data what i expect to see on the serial line and the zero crossing high low toggle line is... garbage, and some times non existant.
I should mention that i have tested this only on a breadboard and only the power supply is connected apart from the leds.
So what do you guys think??
Code errors or breadboard issues due to 20MHz clock??
Instruction timing miscalculations are abundant but atleast the code should blink all the leds equally as the same process is done for all the three phases.
PS: This is not the full version of the code, but this version itself is not working as expected to enable me to progress further.
I do apologize for the lack of more information in the post but the code is reasonably detailed in terms of calculations if not operation.
Thanks in advance!!!
PS again : I was able to edit and insert code after posting. so here it is folks.
/*
* File: main.c
* Author: N S Krishna Chaitanya
*
* Created on 8 August, 2012, 1:24 PM
* Three phase waveform generator
* Processor : PIC16F676
* Clock Frequency : 20MHz
*
* Brief Explanation :
*
* The PIC is connected to three daisy-chained 74HC595 serial - to parallel
* shift registers. The output of the shift registers are connected to 3 DAC0808
* which convert the 8 bit sinewave data into reference voltages for the 3 phases
*
* Three more pins are used to trigger a HIGH-LOW signal for driving the IGBTs.
*
* Pin Connections
*
* RC0 -> Serial Data
* RC1 -> Serial Clock
* RC2 -> Data Latch
*
* RC3 -> R Phase High Low bit
* RC4 -> Y Phase High Low bit
* RC5 -> B Phase High Low bit
*
* Look-up table for DAC consists of 240 samples for half a cycle i.e 10 milliseconds
* Each Phase is associated with an index and the offset w.r.t 0 is added at initialization
* and subsequently index is only incremented by 1 in each invocation of ISR
*
* A Pseudo circular buffer ensures that the index never overflows and wraps around to
* 0th element at which point the respective phase High Low bit is toggled indicating a
* zero crossing.
*
* The PIC "looks ahead" for the next data to be sent presends it in this invocation
* and only "latches" the data on the next invocation of the ISR
* Ensuring that the data appears simultaneously on all the DAC inputs
*/
//Necessary include files and #defines for compiler and __CONFIG() BLOCK
#include <stdint.h>
#include <stdlib.h>
#include <htc.h>
#include <pic.h>
//__CONFIG()
/*
*XT crystal input
*Watchdog timer off
* _MCLRE functions as reset input
* all code protections off
*/
__CONFIG(FOSC_XT & WDTE_OFF & MCLRE_ON & CPD_OFF & CP_OFF & BOREN_OFF);
//External crystal frequency 20MHz with external 22pf ceramic load capacitors
//Required to get the least instruction cycle time
#define _XTAL_FREQ 20000000
//#defines, global variables and function definitions for main()
//Total number of samples in the lookup table for DAC
#define DAC_BUFFER_SIZE 240
//HIGH LOW zero crossing indicators for R,Y,B Phases
#define R_PHASE_HIGH_LOW RC3
#define Y_PHASE_HIGH_LOW RC4
#define B_PHASE_HIGH_LOW RC5
//Serial Data, clock and latch for the PIC
#define SERIAL_DATA RC0
#define SERIAL_CLOCK RC1
#define DATA_LATCH RC2
//Inline function to latch the existing data in the 595 storage register
//to the inputs of the DAC to update the dac in the ISR
#define STROBE_SERIAL_DATA() {DATA_LATCH=0; NOP(); NOP(); DATA_LATCH=1;}
void SETUP_TIMER0(void);
void SEND_SERIAL_DATA();
//240 samples representing half sine wave
const uint8_t DAC_LOOKUP_TABLE[DAC_BUFFER_SIZE]={0,3,5,8,11,13,16,19,21,24,27,29,32,35,37,40,42,45,48,50,53,55,58,
60,63,66,68,71,73,76,78,81,83,85,88,90,93,95,97,100,102,104,107,
109,111,113,116,118,120,122,124,126,128,130,132,135,137,138,140,
142,144,146,148,150,152,153,155,157,159,160,162,163,165,167,168,
170,171,173,174,175,177,178,179,181,182,183,184,185,186,187,188,
189,190,191,192,193,194,195,196,196,197,198,198,199,200,200,201,
201,201,202,202,203,203,203,203,204,204,204,204,204,204,204,204,
204,204,204,203,203,203,203,202,202,201,201,201,200,200,199,198,
198,197,196,196,195,194,193,192,191,190,189,188,187,186,185,184,
183,182,181,179,178,177,175,174,173,171,170,168,167,165,163,162,
160,159,157,155,153,152,150,148,146,144,142,140,138,137,135,132,
130,128,126,124,122,120,118,116,113,111,109,107,104,102,100,97,95,
93,90,88,85,83,81,78,76,73,71,68,66,63,60,58,55,53,50,48,45,42,40,
37,35,32,29,27,24,21,19,16,13,11,8,5,3};
static uint8_t SERIAL_DATA_BUFFER[3];
//SERIAL_DATA_BUFFER[0] is for R Phase
//SERIAL_DATA_BUFFER[1] is for Y Phase
//SERIAL_DATA_BUFFER[2] is for B Phase
static uint8_t R_PHASE_INDEX=0,Y_PHASE_INDEX=80,B_PHASE_INDEX=160;
// Offsets for the lookup table
// 120 degrees phase difference between phases
// 6.6 milliseconds phase difference (time)
// R Phase = 0 milliseconds with High Low Bit = 1
// Y Phase = 6.6 milliseconds with High Low Bit = 0
// B Phase = 13.2 milliseconds with High Low bit = 1
int main()
{
__delay_ms(10);
//Initialize delay for startup time and oscillator stabilization
//Data direction registers and initializations
//Set all the PORTC to outputs and preload to 0
TRISC=0x00;
PORTC=0x00;
NOP();
NOP();
//Phase R and Phase B should trigger high
//But index of Phase R being 0, ISR automatically
//toggles the Phase R High Low Bit
R_PHASE_HIGH_LOW=0;
NOP();
NOP();
Y_PHASE_HIGH_LOW=0;
NOP();
NOP();
B_PHASE_HIGH_LOW=1;
NOP();
NOP();
//Setup TIMER0 to give interrupt every 10 milli-seconds / 240 parts
//Clock is 20 MHz divided by 4 i.e 4 MHz internal clock
//Instruction cycle is 200 nano-seconds
//Minimum prescaler for TIMER0 is 2
SETUP_TIMER0();
//The first element in the serial buffer is R Phase
//The second element in the serial buffer is Y Phase
//The third element in the serial buffer is B Phase
SERIAL_DATA_BUFFER[0]=DAC_LOOKUP_TABLE[R_PHASE_INDEX]; //R Phase Serial Data
SERIAL_DATA_BUFFER[1]=DAC_LOOKUP_TABLE[Y_PHASE_INDEX]; //Y Phase Serial Data
SERIAL_DATA_BUFFER[2]=DAC_LOOKUP_TABLE[B_PHASE_INDEX]; //B Phase Serial data
//Set the Timer0/Counter input to Internal Clock
T0CS=0;
while(1)
{
//Wait for Timer0 interrupt
}
return (EXIT_SUCCESS);
}
void SETUP_TIMER0(void)
{
//Registers associated with TIMER0
//TMR0
//INTCON
//OPTION_REG
//TRISA
//Enable TMR0 interupts, peripheral interrupts, Clear TMR0IF
//Set prescaler to TMR0 and prescaler value to 2
INTCON=0x60;
//Enable Peripheral interrupts, TMR0 interrupts, clears TMR0IF
OPTION_REG=0xF0;
//Set transition to RA2 input, assign 000 prescaler to TMR0
TMR0=255 - 105;
//Preload the timer
//Overflow value for timer is 255
// TIMER0 interrupt should happen every 10 milliseconds / 240 parts
// 41.6 ~ 42 useconds
// with 200 nanoseconds instruction cycle 5 instructions to a useconds
// and 42 * 5 = 210 instructions that can be executed.
// Timer0 preload value
// Full overflow of Timer0 takes 255 * 0.2 useconds = 51 useconds
// With default prescaler of 2 to Timer0 it takes 102 useconds
// i.e 255 count = 102 useconds
// 42 useconds = 105 count
// Value to preload into Timer is (255 - 105)
ei();
//Enable Interrupts
}
void SEND_SERIAL_DATA()
{
//Select each element in the serial buffer from 0 thru 2
for(char i=0;i<=2;i++)
{
//Flush each bit in the present buffer element in the reverse order
//MSB first, LSB last
for(char j=0;j<=7;j++)
{
SERIAL_DATA=(SERIAL_DATA_BUFFER[i])>>(7-j);
//Toggle the serial clock
SERIAL_CLOCK=1;
NOP();
SERIAL_CLOCK=0;
}
}
}
void interrupt Interrupt_Routine(void)
{
//Clears the TIMER0 Interrupt flag
TMR0IF=0;
//Preload timer to give 42 useconds interrupt
//Total instructions available is 210 instructions
//that can be executed before the interrupt occurs again
TMR0=255 - 105;
//Check if any index has wrapped around to 0 and toggle the respective High Low bit
//Indicating that zero-crossing has occured for the respective phase
if(R_PHASE_INDEX==0)
R_PHASE_HIGH_LOW^=1;
if(Y_PHASE_INDEX==0)
Y_PHASE_HIGH_LOW^=1;
if(B_PHASE_INDEX==0)
B_PHASE_HIGH_LOW^=1;
//Latch the data already present on the output of the 595 to the DAC input
STROBE_SERIAL_DATA();
//Pseudo circular buffer for the R,Y,B indexes with wrap around when index reaches
//239th element
R_PHASE_INDEX++ % DAC_BUFFER_SIZE;
Y_PHASE_INDEX++ % DAC_BUFFER_SIZE;
B_PHASE_INDEX++ % DAC_BUFFER_SIZE;
//Acquire the lookup values for the DAC based on present index value
//and store in the serial data buffer
SERIAL_DATA_BUFFER[0]=DAC_LOOKUP_TABLE[R_PHASE_INDEX]; //R Phase Serial Data
SERIAL_DATA_BUFFER[1]=DAC_LOOKUP_TABLE[Y_PHASE_INDEX]; //Y Phase Serial Data
SERIAL_DATA_BUFFER[2]=DAC_LOOKUP_TABLE[B_PHASE_INDEX]; //B Phase Serial data
//Send the present data to the 74HC595 and wait for the next Interrupt
//to signal any zero crossing and latch the 8 bit data to the 595 output
SEND_SERIAL_DATA();
}