Alright, I'm back on this project
I've managed to get my PIC (18f4550, 20mhz HS), a tpic6c595 shift register, and 8 leds all to work properly (for the most part).
The odd thing is, I picked the tpic shift register because its supposed to handle double buffering, to eliminate flicker, but I seem to be getting some flicker anyhow.Each led seems to filcker once or twice a cycle (of my little pattern), never quite at the same interval, and none at the same time.
I'm also having a little trouble fully understanding how this particular pick handles the OSC configuration, AFAICS, it should be running at 48mhz given my config, yet the math in my code only seems to work out properly when I assume its running at 20mhz.
I'm likely getting several things wrong, hopefully some of you can help
Code: Select all#include <p18f4550.h>
#include <delays.h>
#include <timers.h>
#pragma config FOSC = HSPLL_HS
#pragma config PLLDIV = 5
#pragma config CPUDIV = OSC1_PLL2
// The above should give 4mhz to the pll, and 48mhz to the cpu
// It doesn't seem to be doing so, hence the MCU_FREQ=20000000
#pragma config PWRT = ON
#pragma config WDT = OFF
#pragma config LVP = ON
#pragma config MCLRE = ON
#pragma config ICPRT = ON
#pragma config DEBUG = OFF
#define MCU_FREQ (20000000)
#define MCU_IPS (MCU_FREQ/4)
#define PWM_DEVICES 8
#define PWM_FREQ 120
#define PWM_DUTY 256
#define PWM_PERIOD (MCU_IPS/(PWM_FREQ*PWM_DUTY))
#define TIMER_START (65536-PWM_PERIOD)
void set_timer(unsigned int val)
{
TMR0H = val << 8;
TMR0L = val & 0x0f;
}
#define sb(d,b) ( (d) |= (1<<b) )
#define cb(d,b) ( (d) ^= ~(1<<b) )
volatile unsigned char *_pwm_data = 0;
volatile unsigned char _pwm_duty[PWM_DEVICES];
void pwm_duty(unsigned char chan, unsigned char d)
{
_pwm_duty[chan] = d;
}
volatile unsigned char _pwm_state[PWM_DEVICES];
void pwm_state(unsigned char chan, unsigned char s)
{
_pwm_state[chan] = s;
}
volatile unsigned char _pwm_timer_tick = 0;
void pwm_timer_tick(void)
{
unsigned char i;
_pwm_timer_tick++;
for(i = 0; i < PWM_DEVICES; ++i) {
if( _pwm_timer_tick == 0 && _pwm_duty[i] != 0 ) { // reset at start
cb(*_pwm_data, i); // clear bit
_pwm_state[i] = 0; // off
}
else if( _pwm_timer_tick == _pwm_duty[i] && _pwm_duty[i] != PWM_DUTY ) {
sb(*_pwm_data, i); // set bit
_pwm_state[i] = 1; // on
}
}
}
void pwm_init(unsigned char *data)
{
unsigned char i;
_pwm_data = data;
for(i = 0; i < PWM_DEVICES; ++i) {
pwm_duty(i, 127);
pwm_state(i, 1);
}
}
void spiWrite(unsigned char byte);
void MyWriteUSART(unsigned char ch);
void Delay(unsigned long cntr)
{
while(cntr > 0) cntr--;
}
volatile unsigned char leds = 1;
#pragma interrupt high_isr
void high_isr(void)
{
if(INTCONbits.TMR0IE == 1 && INTCONbits.TMR0IF==1) {
pwm_timer_tick();
spiWrite(leds);
WriteTimer0(TIMER_START);
INTCONbits.TMR0IF = 0;
}
}
#pragma code intVector = 0x08
void intVector(void) {
_asm
goto high_isr
_endasm
}
#pragma code
#define nop() _asm nop _endasm
#define latch() L_CLK = 0; nop();nop();nop();nop(); L_CLK = 1
#define clear() CLR = 0; nop();nop();nop();nop(); CLR = 1
#define CLR LATBbits.LATB0
#define S_CLK LATBbits.LATB2
#define L_CLK LATBbits.LATB1
#define DATA LATBbits.LATB4
void spiWrite(unsigned char byte)
{
static unsigned char i = 0; // loop counter
static unsigned char j = 0; // delay counter
// clear();
S_CLK = 0; // Ensure SCK is low
// latch();
for (i = 0; i < 8; i++) // Loop through each bit
{
if (byte & 0x80) // Check if next outbit is a 1
{
DATA = 1; // If a 1, pull SO high
}
else
{
DATA = 0; // If a 0, pull SO low
}
byte = byte << 1; // Shift outbyte left for next bit
S_CLK = 1; // Bring SCK high to latch bit
for (j = 0; j < 4; j++)
{
nop(); // Avoid violating Thi
}
S_CLK = 0; // Bring SCK low for next bit
nop();nop();nop();nop();
}
latch();
}
void main(void)
{
unsigned int duty[PWM_DEVICES] = { 127, 127, 127, 127, 127, 127, 127, 127 };
char dir[PWM_DEVICES] = { 1, -1, 1, -1, 1, -1, 1, -1 };
unsigned char i;
unsigned int count = 0;
ADCON1 = 0xf;
TRISE = 0x00;
PORTE = 0xf;
RCONbits.IPEN = 1;
INTCONbits.GIE = 1;
INTCONbits.PEIE=1;
INTCON2bits.T0IP = 1;
// init pwm routines.
pwm_init(&leds);
// Init Timer0
OpenTimer0 (TIMER_INT_ON & T0_SOURCE_INT & T0_16BIT);
WriteTimer0(TIMER_START);
TRISBbits.TRISB0 = 0;
TRISBbits.TRISB1 = 0;
TRISBbits.TRISB2 = 0;
TRISBbits.TRISB4 = 0;
nop();
clear();
spiWrite(0xAA);
while(1) {
Delay(50);
PORTEbits.RE1 ^= 1;
for(i=0; i < PWM_DEVICES; ++i) {
duty[i] += dir[i];
if(duty[i] >= 255 || duty[i] <= 0) {
dir[i] = -dir[i];
duty[i] += dir[i]; // go back within bounds
}
pwm_duty(i, duty[i]);
}
}
}
Just a little note, the reason I have the PWM_FREQ up at 120, is because I can't stand it at 60hz, I can see the refresh, even at 85 it was slightly annoying.