SparkFun Forums 

Where electronics enthusiasts find answers.

Have questions about a SparkFun product or board? This is the place to be.
By winston
#31592
Tomasu wrote:Mine won't :) This project is all about the leds. I'm hoping a 18F4550 can handle it at full blast. (48mhz, 12mips or so)
Consider using an Atmel AVR - it can do roughly 12 mips at 12 MHz (meaning your clock circuit is far more forgiving of stray capacitances, and generally less power will be needed although I suspect the power required by the uC is a fraction of what you need to drive the LEDs!)
By Morrog
#31593
You can fit the SRs and resistors all on one breadboard.

winston reminded me: You'll want to be careful with your power supply. If you use a voltage regulator, most aren't designed for more than 1amp of current. 60 LEDs at 20mA will be 1.2amps. I suggest using 3 voltage regulators. 1 to provide power to the uC, and 2 for the LEDs, one per half.
By Tomasu
#31596
Consider using an Atmel AVR
I've heard that. And I just might, but I have some free samples from PIC to burn through ;)
I suspect the power required by the uC is a fraction of what you need to drive the LEDs!
Quite. The pic needs a whole few mA. I can't remember off hand, but its not anywhere near what the leds will use :)
60 LEDs at 20mA will be 1.2amps.
That of course is worst case senario. I doubt the LEDs will actually use up 1.2mA while they are being pwm'ed. I could be wrong though.
I suggest using 3 voltage regulators. 1 to provide power to the uC, and 2 for the LEDs, one per half.
Sounds like a plan. I have some vrs laying around that I'll probably end up using for the final layout, but for now I have a nice benchtop psu (home made, but decent), and I doubt I'll be going right to 60 leds right off the bat. probably start with like 8 (one SR). and work my way up.

I really appreciate all the input guys. :)
By emf
#31601
Tomasu wrote:
Resistors are dirt cheap.
Yup. and I have a boat load. Though after hooking up that many resistors I might want to go smt ;D just to save space... 60 resistors. hmmm.
You might want to pick up some resistor networks next time you order from a big parts store. They come in lots of shapes and sizes, but the eight resistor 9-pin SIP variety is common and easy to work with. Tie one pin to power or ground and the other eight to eight LEDs. A network takes up roughly the same amount of space as two resistors and you'll only have to drill/solder about half as many holes/pins. They come in surface-mount varieties too, but many of them aren't able to handle enough power for 8 LEDs at full blast so double-check before you order.
By Tomasu
#31602
I was thinking a resistor network would do, but I didn't bother actually looking it up. Thanks for the tip. I need to order some transistors and diodes and some more LEDs so I'll see if the place has resistor networks.
By saipan59
#31624
I'm hoping a 18F4550 can handle it at full blast. (48mhz, 12mips or so).
Consider using an Atmel AVR - it can do roughly 12 mips at 12 MHz
If the AVR is running 12 mips from a 12 Mhz clock, it is very likely using a PLL to multiply the clock frequency internally.
In any case, the PIC is the same - you can run it from a 12 Mhz crystal with a 4X PLL to get 48 Mhz (12 MIPS), or you can run it from a 48 Mhz external oscillator. And there are several other oscillator choices with the PIC (and probably with the AVR also).

A bit of soapboxing:
Be suspicious of any claim that Atmel, Microchip, or Freescale, or whatever is "better" than something else. They all have very similar capabilities, and you have to look at specific features in detail to really say which one is best for your application. In another forum, some guy made a claim of "AVRs run circles around PICs!", which is of course a ridiculous statement. It just means that the guy had spent his money on AVR chips and programmers and such...

Pete
By Morrog
#31632
Don't AVRs have free C compilers? If so, that's reason enough to go AVR. I know of no free C compilers (without restrictions) for PICs. There is the GCC toolchain for PIC, but it doesn't support 18f.
By winston
#31649
saipan59 wrote: If the AVR is running 12 mips from a 12 Mhz clock, it is very likely using a PLL to multiply the clock frequency internally.
No, the AVR is pipelined (so it's fetching the next instruction as the current one is executing) to get higher throughput per clock. Regardless of how they do it - whether it's pipelining or an internal multiplier - the lower frequency you have on your PCB, the more forgiving it will be to lay out (which is something important when you're starting out).

Having said that, the AVR will be "almost 12 mips" because branch instructions may cause the uC to have to throw away what's in the pipeline if the branch didn't go to the instruction that was being loaded.
By saipan59
#31658
Don't AVRs have free C compilers? If so, that's reason enough to go AVR. I know of no free C compilers (without restrictions) for PICs. There is the GCC toolchain for PIC, but it doesn't support 18f.
Very often "you get what you pay for". But in any case, the restrictions on the "free" PIC compilers are minimal, and most folks (especially hobby users) won't notice. For example, the free versions of Microchip's C18 and C30 compilers are only missing some optimization features - unless you're pushing things to the limit (code size and/or speed), it doesn't matter. There are also free versions of Hi-Tech C and (I believe) CCS, which I think are also quite useful.
No, the AVR is pipelined (so it's fetching the next instruction as the current one is executing) to get higher throughput per clock. Regardless of how they do it - whether it's pipelining or an internal multiplier - the lower frequency you have on your PCB, the more forgiving it will be to lay out (which is something important when you're starting out).
Mid-range PICs have a two-stage pipeline described in their docs. So again, I'm saying that there's not a heck of a lot of difference between the brands, unless we get specific about some detailed requirements. It's not adequate to say "an AVR does 12 MIPS", and draw any real conclusions from that. You have to look at real throughput doing whatever your application requires. For example, blinking LEDs (as discussed in this thread) may use resources that are largely unrelated to a "MIPS" rating.
I am admittedly a PIC bigot because that's where I've got my experience and investment.
I do agree with you about the lower frequencies on the board, but I'm thinking that any of the major MCU brands will let you achieve that.

BTW, it seems unlikely that this LED-blinking application requires particularly high processing speeds. So it might be more useful to choose an MCU based on things like on-board PWM controllers and general-purpose I/O pins and such.

Pete
By wiml
#31753
SDCC will produce PIC code, but I don't know how its generated code compares to other compilers. (I've only used SDCC for 8051s, and I use gcc for AVRs; I don't do PICs any more...)
By busonerd
#31802
I've had issues with SDCC generating incorrect pic code - but this was long ago, probably has been fixed by now.

Cheers,

--David Carne
By Tomasu
#40442
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.
By oPossum
#40443
Tomasu wrote:
Code: Select all
#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
Does that really work as intended? Try making latch() and clear() inline...
Code: Select all
inline void latch(void)
{
 L_CLK = 0;
 _asm
 nop
 nop
 nop
 _endasm
 L_CLK = 1;
}

inline void clear(void)
{
 CLR = 0;
 _asm
 nop
 nop
 nop
 _endasm
 CLR = 1;
}
By Tomasu
#40445
This version of C18 doesn't seem to support the "inline" keyword. And it seems C18 also treats "nop" as if you want to expand "nop()" which is just silly.

Changed to regular functions, and it works just as well as it did before. Much cleaner code though :)
By NleahciM
#40450
saipan59 wrote:
Don't AVRs have free C compilers? If so, that's reason enough to go AVR. I know of no free C compilers (without restrictions) for PICs. There is the GCC toolchain for PIC, but it doesn't support 18f.
Very often "you get what you pay for".
I agree. However, in the case of AVR GCC (a free C compiler for AVRs) - you get a top notch product for free.

On AVRfreaks.net there have been various comparisons between AVR GCC and the various commercial compilers - and the main differences people normally find are a matter of personal taste.