Fab15 part II

Here is the REV.2 board.It’s far more compact, around 38mm x 38mm, and is stackable.

The ICSP acts as a connector linking the top and bottom boards, with one extra pin for the Vout from the LTC3105 to the RF transciever. The idea is to use long pins which will pass through the board but allow a ISCP header to plug in top so it remains programmable.

I have added a ground plane and made sure to make leads thick and short for decoupling caps connected to Vin and Vout.

In this version the solar panels don’t live on a board but instead float above the sandwich.

The board is still basic, it doesn’t allow for PGOOD, SHUTDOWN from LTC3105 nor does it have the diode and cap in series for MPPC. I have also not switched over the the RFM69 as I cannot find anyone who has made it work with the Attiny2313. It does have an I2C LUX sensor included on the solar harvesting board though, it speaks to the microchip on the other board via the ICSP header.

I did a little touching up of the inverted eagle image, I find the ground planing leaves some ugly left over bits. I set distances to .6mm for the ground plane and used .4mm thick traces elsewhere apart from power traces which I made at 1mm. I made the cut out holes .68mm which is the width I measure of a header pin. Making this work nicely will be trail and error I suspect.

I have a hole cut through the top board to allow the antenna to pass through, not sure if this is sacrilege or not but I thought it was nifty.

I have ordered some Attiny2313Vs in SOIC package, LTC3105s, Vishay’s VEML6030 I2C LUX sensor (datasheet: http://www.farnell.com/datasheets/2118174.pdf?_ga=2.101548161.1466299159.1558364926-1966659865.1549463489&_gac=1.82301412.1555072928.Cj0KCQjw7sDlBRC9ARIsAD-pDFol1bBBXfgfW_WkUDGae3GBfZ2j4YvsX5g-ECjGaAFDm9bDDEVXEwgaAkgpEALw_wcB) -I edited the TSL2561 from Sparkfun in Eagle- and some 10F supercapacitors. I have also found a Coilcraft inductor (LPS4018-103MRB) which matches the specs for the LT demo board.

Here’s the board:

And here’s the schematic:

I am also thinking about the indoor/outdoor-ness of this project. If this is placed outdoor it should be potted in resin with maybe a way to strap it to a post or magnetically place it somewhere (is a mini suction cup a real solution?). If there are dual axis motors moving this thing around I could imagine the circuit being inside a kind of clear plexiglass dome, the indoor version wouldn’t need this of course.

So, if everything miraculously works with the circuit I can move to add a dual H-bridge to move this panel around. I could possibly put this on the flip side of one of these double sided boards and use our rivets if necessary…Though I would need to first source some nice motors from one of our approved suppliers. I need a small DC motor with a gear reduction that runs at 3V for 5 euros. Solarbotics seems to be the best source for these, I especially like this https://solarbotics.com/product/gm23/ .

Here is the first attempt at lasercutting on double sided FR4:

Evidently the holes for the passage of pins did not work out. For next time remember that you have to first ablate the metal with the Fiber laser before you can use the C02 laser. Once you get through the fiberglass you need to take out the copper at the reverse side, if you’re using a double sided board, so this requires switching back to the Fiber laser?

In any case, the holes for pins passing through need to be much smaller and the copper traces need to be much bigger. This board will at least serve to test with the newly arrived LTC3105 to see if that circuit can get going.

The parts have arrived, here is the test set up I have got:

The voltage of the small 24 x 33mm solar panel from Solarbotics is around 4.7V, so under the 5V max of the unit. I can confirm that Vin and GND are shorted together by the LTC3105 and so if you see a short there it’s not a problem. I can also confirm that power supplies will give funny readings when supplying the LTC, this appears to be because the device is pulling and pushing current around and making it difficult to tell exactly how much voltage is going where. When I test my solar panels disconnected I get several volts and when I test again while they are plugged in to the LTC I get only a few tens of millivolts.

The 10F supercap is slowly charging, but the light is too strong and is melting the solar panel! I’m concerned that it takes so long to get the LDO going with the solar panels. Using the power supply I can get LDO up and running at very low voltages.

The kxob22 solar cells I am using are super sensitive to soldering temperature, max 220 C for them, this is not enough to melt leaded solder in my experience. I just destroyed 10 of them by accident…

http://ixapps.ixys.com/DataSheet/20110302-KXOB22-12X1-DATA-SHEET.pdf

In principle the idea was to connect four or five in series (plus to minus) to get around 2.5V in total, hitting the efficiency sweet spot of the LTC3105 of 90%+.

Things are looking good charging with a 10V 4700uF cap. It is slowly charging (at 2.8V now) with an Attiny2313V plugged in and waiting for LDO to come on. The Attiny2313 doesn’t seem to be frustrating the charging process, disconnecting it has little effect on the charging. It looks like even when the Vout has reached its target voltage it is not turning on the LDO. Could this be because I accidentally put the Vin too high when testing with the power supply? The datasheet explains that the Vout is not charged until the LDO regulation is met…What’s going on here?

The next question, if this test works, is if a 4700uF cap charged to 3V can power the RFM12B. In previous tests I found that anything less than 2.7V was insufficient for a signal to be received. It looks like it works about 13 of the time with a 4700uF and the Attiny2313V TX circuit I made. With the 10F 3V supercap charged up to 2.9V the RFM12B works nicely…but how to use the LTC3105 to charge such a big cap when it is having difficulty with a .005F….Maybe trying a 0.5F (two 1F 2.5V in series). This works well, no problems transmitting around four times on a full charge. Maybe the magic number is .1F?

WOW! Major change on functionality when I activate MPPC. Almost instantly I hit LDO and start charging the cap. Completely different operation now. Suddenly everything seems possible with this device and this project :). Attaching the RF12B and turning it on once the cap has fully charged successfully sends a trasmission and is fully recharged ten seconds later…Ahh the sweet taste of a working IC.

Moving on to the MOSFET switching, it appears that the microchop voltage of 2V is too low to turn on the transistor very much. I switched to an SMD MOSFET which has a minimum Vgs of 1V and max of 2V. It seems to work now once I add a 10K pull up resistor on the Gate. I’m using the 512-RFD16N05LSM9A.

Replaced the Attiny2313V with an Attiny44A and it’s hogging so much power Vout is decreasing under the same conditions…turns out it’s important to have the microchip exploiting sleep etc.

OK, I’ve got things working such that the moment a HIGH signal is seen by PD6 on the Attiny (from LTC3105’s PGOOD) it beings transmitting. Right now it’s not optimized to use minimal power while waiting but I can work on this next if everything goes smoothly with this test.

Current problem is that once the microchip has slept and let the cap charge up, it sends a transmission and then the cap drains quite rapidly until I hit reset. I think the MOSFET is somehow staying on? I could measure the current draw of the different modules and see whats happening. Another idea is to put the RFM12 initialization AFTER I check that the PGOOD is HIGH.

I have decided to make my life easier and to change to INT1 from PCINT0. INT0 and INT1 can be set up to trigger on RISING or FALLING signals wherease PCINTx only trigger on pin changes, which is causing my code to be more complicated than it needs to be. Here is how the code should work:

The problem with this though is that the interrupt will only work when PGOOD turns on and the state of the pin CHANGES. Once PGOOD is on and stays on it can’t wake up the ATTINY. So before going to sleep the ATTINY needs to make sure PGOOD is OFF (so that it can be awoken by PGOOD going ON). So I need to add a while loop that says which PGOOD is high send transmissions.

I like that this project is making me more connected to the sun. I can’t work without it and I have become much more dependent on good weather to continue working. It makes one think of all the ecology applications this kind of device has too.

Grrrr…wasted an hour plus today learning that in POWER_DOWN mode only LEVEL interrupts for INT0 and INT1 will function (not rising/falling edge or voltage changes). From IDLE mode these work, however.

Here’s the code which works when testing in isolation. Once I connect INT0 to power it wakes up and sends stuff. When reconnected to GND it goes back to sleep to wait for another interrupt. Cool. To get this working with PWR_DOWN I need to add an inverter (as only LOW signal can be detected from deep sleep by INT0 and we get a HIGH from PGOOD).

I have only tested this with a power supply, need to now test with sun (weather didn’t permit this today).

*THIS DOESN’T WORK WITH THE LTC3105. The next code does though further down.

/*
 * Attiny2313 sleep + RFM12B + ltc3105.c
 *
 * Created: 5/27/2019 3:47:37 PM
 * Author : FablabDigiscope
 */ 


#define F_CPU 8000000 

#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <util/delay.h>

/* RFM12B INTERFACE */
#define SCK 7 // SPI clock
#define SDO 6 // SPI Data output (RFM12B side)
#define SDI 5 // SPI Data input (RFM12B side)
#define CS 4 // SPI SS (chip select)
#define NIRQ 2 // (PORTD)

/* IO CONTROL */
#define HI(x) PORTB |= (1<<(x))
#define LO(x) PORTB &= ~(1<<(x))


/* MOSFET */
#define MOSFET 4
#define MOSFET_OFF() PORTD &= ~(1<<MOSFET)
#define MOSFET_ON() PORTD |= (1<<MOSFET)


void portInit() 
{
	HI(CS);
	HI(SDI);
	LO(SCK);
	DDRB = (1<<CS) | (1<<SDI) | (1<<SCK);
	DDRD |= (1<<MOSFET);
}

unsigned int writeCmd(unsigned int cmd) 
{
	unsigned char i;
	unsigned int recv;
	recv = 0;
	LO(SCK);
	LO(CS);
	
	for(i=0; i<16; i++) {
		if(cmd&0x8000) HI(SDI); else LO(SDI);
		HI(SCK);
		recv<<=1;
		if( PINB&(1<<SDO) ) {
			recv|=0x0001;
		}
		LO(SCK);
		cmd<<=1;
	}
	HI(CS);
	return recv;
}


void rfInit() 
{
	writeCmd(0x80E7); //EL,EF,868band,12.0pF
	writeCmd(0x8239); //!er,!ebb,ET,ES,EX,!eb,!ew,DC
	writeCmd(0xA640); //frequency select
	writeCmd(0xC647); //4.8kbps
	writeCmd(0x94A0); //VDI,FAST,134kHz,0dBm,-103dBm
	writeCmd(0xC2AC); //AL,!ml,DIG,DQD4
	writeCmd(0xCA81); //FIFO8,SYNC,!ff,DR
	writeCmd(0xCED4); //SYNC=2DD4 ,AG
	writeCmd(0xC483); //@PWR,NO RSTRIC,!st,!fi,OE,EN
	writeCmd(0x9850); //!mp,90kHz,MAX OUT
	writeCmd(0xCC17); //OB1,ACOB0, LPX,Iddy,CDDIT,CBW0
	writeCmd(0xE000); //NOT USED
	writeCmd(0xC800); //NOT USED
	writeCmd(0xC040); //1.66MHz,2.2V
}


void rfSend(unsigned char data)
{
	while(PIND&(1<<NIRQ));
	writeCmd(0xB800 + data);
}


void sleep()
{
	set_sleep_mode(SLEEP_MODE_IDLE); //select PWR DOWN, the most power savings
	sleep_enable(); //set  SE bit
	sei(); // enable global interrupts
	sleep_cpu(); //actually sleep
	sleep_disable(); //code reaches this point after interrupt
}


ISR(INT1_vect) //PB0 level change
{
	//do nothing
}



int main(void)
{

		
			portInit();
			GIMSK |= (1 << INT1); // enable the  external interrupt on pin PD3
			MCUCR |= (1<<ISC11) | (1<<ISC10); //set to rising edge triggered

while(1)
	
	if(PIND & (1<<PD3))
	{
	cli(); 
	
	HI(CS);
	HI(SDI);
	LO(SCK);
			
				MOSFET_ON();
				volatile unsigned int i,j;
				for(i=0;i<1000;i++)for(j=0;j<123;j++);
				rfInit();
				portInit();
				writeCmd(0x0000);
				rfSend(0xAA); // PREAMBLE
				rfSend(0xAA);
				rfSend(0xAA);
				rfSend(0x2D); // SYNC
				rfSend(0xD4);
				for(i=0; i<1; i++) 
				{
					rfSend(0x30+i);
				}
				rfSend(0xAA); // DUMMY BYTES
				rfSend(0xAA);
				rfSend(0xAA);		
				for(i=0; i<10000; i++) // some not very
				for(j=0; j<123; j++); // sophisticated delay
	}

else
{
		MOSFET_OFF();
		sleep();
}
}

So what works well with a power supply does not appear to work well in practice with the LTC3105. Things work the first time then either slowly drain the battery mysteriously or don’t drain the battery at all and sleep on a full capacitor!

Another idea is to have the chip wake up from PGOOD and then just drain the cap until the brown out detector resets the machine when LDO collapses. This is extremely wasteful but is one way to be sure we go from awake state into sleep state based on power levels.

I think one issue is that PGOOD goes up and then down so fast that checking its state in code after it causes an interrupt is not useful.

OK, here it is, the WORKING code! Something happens in the TX code that just continues to drain the cap no matter what kind of interrupt scheme I use so my solution is brute force, reset the entire thing every 8 seconds, poll PGOOD, then transmit until PGOOD goes low or the 8 second reset comes along to wipe the slate clean.


/*
 * Attiny2313 sleep + RFM12B + ltc3105 REV.2.c
 *
 * Created: 5/31/2019 11:21:27 AM
 * Author : FablabDigiscope
 */ 


#define F_CPU 8000000 

#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <util/delay.h>

/* RFM12B INTERFACE */
#define SCK 7 // SPI clock
#define SDO 6 // SPI Data output (RFM12B side)
#define SDI 5 // SPI Data input (RFM12B side)
#define CS 4 // SPI SS (chip select)
#define NIRQ 2 // (PORTD)

/* IO CONTROL */
#define HI(x) PORTB |= (1<<(x))
#define LO(x) PORTB &= ~(1<<(x))




/* MOSFET */
#define MOSFET 4
#define MOSFET_OFF() PORTD &= ~(1<<MOSFET)
#define MOSFET_ON() PORTD |= (1<<MOSFET)

volatile unsigned short int flag; // variables that are changed in ISR should be global AND volatile

void portInit() 
{
	HI(CS);
	HI(SDI);
	LO(SCK);
	DDRB = (1<<CS) | (1<<SDI) | (1<<SCK);
	DDRD |= (1<<MOSFET);
}

unsigned int writeCmd(unsigned int cmd) 
{
	unsigned char i;
	unsigned int recv;
	recv = 0;
	LO(SCK);
	LO(CS);
	
	for(i=0; i<16; i++) {
		if(cmd&0x8000) HI(SDI); else LO(SDI);
		HI(SCK);
		recv<<=1;
		if( PINB&(1<<SDO) ) {
			recv|=0x0001;
		}
		LO(SCK);
		cmd<<=1;
	}
	HI(CS);
	return recv;
}


void rfInit() 
{
	writeCmd(0x80E7); //EL,EF,868band,12.0pF
	writeCmd(0x8239); //!er,!ebb,ET,ES,EX,!eb,!ew,DC
	writeCmd(0xA640); //frequency select
	writeCmd(0xC647); //4.8kbps
	writeCmd(0x94A0); //VDI,FAST,134kHz,0dBm,-103dBm
	writeCmd(0xC2AC); //AL,!ml,DIG,DQD4
	writeCmd(0xCA81); //FIFO8,SYNC,!ff,DR
	writeCmd(0xCED4); //SYNC=2DD4 ,AG
	writeCmd(0xC483); //@PWR,NO RSTRIC,!st,!fi,OE,EN
	writeCmd(0x9850); //!mp,90kHz,MAX OUT
	writeCmd(0xCC17); //OB1,ACOB0, LPX,Iddy,CDDIT,CBW0
	writeCmd(0xE000); //NOT USED
	writeCmd(0xC800); //NOT USED
	writeCmd(0xC040); //1.66MHz,2.2V
}

void sleep()
{
	set_sleep_mode(SLEEP_MODE_PWR_DOWN); //select PWR DOWN, the most power savings
	sleep_enable(); //set  SE bit
	sei(); // enable global interrupts
	sleep_cpu(); //actually sleep
	sleep_disable(); //code reaches this point after interrupt
}



void rfSend(unsigned char data)
{
	while(PIND&(1<<NIRQ));
	writeCmd(0xB800 + data); //TX is ready
}



void initWTD(void)
{
	WDTCSR |= (1<<WDE); //enable Watchdog Timer RESET MODE
	WDTCSR |= (1<<WDP3) | (1<<WDP0); //set to 8 seconds
	sei();//enable global interrupts
}


void shutdown()
{
		HI(CS);
		HI(SDI);
		HI(SCK);
		MOSFET_OFF();	
}

// ISR(WDT_OVERFLOW_vect) //PD3 level change
// {
// 	if(PIND& (1<<PD3))
// 	{
// 	flag = flag + 1;
// 	}
// 	else
// 	{
// 	flag = 0;	
// 	}
// 
// }



int main(void)
{
	
	 initWTD();
				
		while(1)
		{
			DDRD |= (1<<MOSFET); // get rid of this if code not working!
			shutdown();
			
					if(PIND &(1<<PD3))
					{
					portInit();
					MOSFET_ON();
					volatile unsigned int i,j;
					for(i=0;i<1000;i++)for(j=0;j<123;j++);
					rfInit();
					portInit();
					writeCmd(0x0000);
					rfSend(0xAA); // PREAMBLE
					rfSend(0xAA);
					rfSend(0xAA);
					rfSend(0x2D); // SYNC
					rfSend(0xD4);
					for(i=0; i<16; i++)
					{
						rfSend(0x30+i);
					}
					rfSend(0xAA); // DUMMY BYTES
					rfSend(0xAA);
					rfSend(0xAA);
					for(i=0; i<10000; i++) // some not very
					for(j=0; j<123; j++); // sophisticated delay
					}											
					
					else
					{
						shutdown();
						sleep();
					}
}
}

Here is the code flow diagram:

Some random things I learned about interrupts:

-keep ISRs short and sweet, preferably just to set a flag or get out of sleep. Don’t use delay or call functions within an ISR. -level sensing is the only interrupt that still works for INT0 and INT1 in deep sleep (power-down mode) -the watchdog timer can save you from getting stuck in a piece of code. -the watchdog timer can sleep you for a maximum of 8 seconds.

Just for fun I tested if the LTC3105 could power an h-bridge and turn a motor. While it can power a motor directly, the transistors I was using were consuming massive amounts when off (more than 100mV). I moved to using a mosfet to turn on/off the entire h-bridge but ran into trouble here. I think my best option is to make a practice h-bridge pcb circuit which uses the low VGS MOSFETs we have in the lab. These will include noise reduction and pull down resistors.

UPDATE

Curiously the radio works even better when the RF module is plugged-in to LDO and the microchip is plugged in to Vout…In either case the microchip draws around 2 to 3.5mA and the RF module draws between 13 and 23mA. Taking off the LED from the MOSFET pin improves performance and adding a code that would check PGOOD is still good after a minute would makes things even better I would assume.

UPDATE

Here is the Rev.4 board based on a mirrored sandwhich principle one slice of which is double-sided. The boards include DRV8837 motor drivers which work with low voltages (http://www.ti.com/lit/ds/symlink/drv8837.pdf). It operates on a motor power supply voltage from 0 to 11 V, and a device power supply voltage of 1.8 V to 7 V and a sleep pin. The only difficulty is the package size which will require the use of the reflow oven. The idea with the drivers is to run a pair of motors to adjust the angle of the panels. This will be a first test to see if this is feasable but I don’t doubt that 1/2F cap has enough juice to run a small DC gearmotor for less than a second.

Here is the schematic which shows the three seperate circuits:

And here is how I imagine everything coming together:

Here are the Rev.5 boards, they are on double sided FR1. Cutting all the way through is not nice but the quality of the cut side is very nice. I lost a trace while cleaning but otherwise these turned out well.

And here is the backside of the microchip board. I didn’t do a sufficient number of passes and had to go around with an exacto knife to finish it off.

REFLOWING

The VEML6030 datasheet explains the maximum temperatures for reflow:

I am using the XG-Z40 solder paste: https://www.mouser.com/datasheet/2/265/tds-4860P-952714.pdf

  • Continued on the following page…