Sunday, July 28, 2019

0000 0000 0000 0101

AT24C256 EEProm Module (take two)


You could be forgiven for having a feeling of Déjà vu as I drag out the old AT24C256 module again for this blog entry. The origin of my interest in this component is the idea of either data logging (e.g. temperature, humidity, water level) or reading large amounts of data (e.g. music, voice, text) where the data is processed by a smaller chip that lacks memory (such as the Attiny85 I'll be using this week).

So last week I rather flippantly wrote "next week I think I'll look at using a small memory attiny chip to play some music using the external memory of this EEProm chip", thinking that this blog entry should be a natural and easy extension of last week when I wrote and retrieved single characters to and from the EEProm.

Not so!

Deciding to use the tone library to make music, it soon became evident that the data I wrote to the EEProm was coming back as weird noise. The problem was that the data was writing as single bytes (0-255), but I need integer values (0 to 65535) to represent frequencies audible to the human ear. So each note (and it's duration) needed two EEProm addresses.

I was futzing about with the code and having a few head scratching moments, but as usual a good sleep and a bit of spreadsheet magic helped the thought processes. I wanted to write two different songs on two EEProm modules using a beefy Arduino Uno and then swap them in and out to an Attiny85 doing the reading and playing. The "songs" as notes and durations look something like:


// imperial march

const int song[] PROGMEM =
{
  17, 2, 440, 2, 17, 2, 440, 2, 17, 2,
  440, 2, 17, 2, 349, 2, 523, 2, 440, 2,
  17, 2, 349, 2, 523, 2, 440, 8, 17, 2, 17, 8
};


// random notes

const int song[] PROGMEM =
{
  218, 4, 559, 3, 17, 2, 459, 4, 17, 2,
  342, 3, 302, 4, 893, 2, 17, 2, 952,3,
  779, 4, 17, 2, 992, 2, 285, 2, 17,2,
  // ...etc...
  657, 2, 17, 2, 535, 4, 17, 2, 862, 2,
  744, 2, 417, 3, 17,2, 615, 3, 17, 2
};

The appearance of the {17, 2} pair signals the player to "play" a pause. The critical piece of code splits each note (and duration) into a upper and lower byte of a 16 byte integer as shown by this spreadsheet snippet.

As each integer is written (or read) the EEProm address is incremented and the integer split (or combined) as follows.

Writing the song:
void writeonce() {
  int eepromaddress;
  for (int thisone = 0; thisone < sizeofarray; thisone++) {
    int thisnumber = pgm_read_word_near(&song[thisone]);
    eepromaddress = thisone * 2;
    writeEEPROM(ext_eeprom, eepromaddress, highByte(thisnumber));
    writeEEPROM(ext_eeprom, eepromaddress + 1, lowByte(thisnumber));  
    }
}

Reading the song:
void readonce() {
  int eepromaddress, mynote, myduration;
  for (int thisone = 0; thisone < 511; thisone++) {
    int mynote, myduration;
    byte readhigh, readlow;
    eepromaddress = thisone * 2;
    readhigh = readEEPROM(ext_eeprom, eepromaddress);
    readlow = readEEPROM(ext_eeprom, eepromaddress + 1);
    mynote = word(readhigh,readlow);
    thisone++; //duration
    eepromaddress = thisone * 2;
    readhigh = readEEPROM(ext_eeprom, eepromaddress);
    readlow = readEEPROM(ext_eeprom, eepromaddress + 1);
    myduration = word(readhigh,readlow)*tempo;
    }
}

The entire code for writing the song can be found here, and for reading and then playing the song here.

So here is a picture of the final circuit showing the USBASP programmer on the right connected to the lovely development board from Łukasz and then onto a small blue breadboard with the EEProm module, speaker and a smoothing capacitor. I'm not sure why there is a smoothing capacitor as the music quality is not really an issue when the notes are a bit random!



And finally let the noise begin, here is the "music" being played live.




Thursday, July 18, 2019

0000 0000 0000 0100

AT24C256 EEProm Module


This week's lucky component is the AT24C256 external EEProm module. I have a few of these in "raw chip" form, which work fine, but the joy is doubled at least through the use of the module version which has the requisite connections, resistors and jumpers as shown below.

Bought at a bargain price (AUD 1.26), these are great not only for development but also the programming of the EEProm chips prior to using them in a project. 

The jumper labelled (WP) as shown above enables writing to the EEProm. The other jumpers set the I2C address of the module at 0x50. If you move the A0 jumper for instance, the address will shift to 0x51, and so on, which allows multiply daisy-chained modules with separate addresses.

Connecting SDA with A4 on the Nano, and SCL with A5 enables communication between the EEProm and the Arduino.

Next you're going to need some some code! It's nice to use an I2C scanner to confirm the correct EEProm address and that everything is ready to go for reading and writing.

I then modified this code to produce a simple sketch to write and then read "HELLO!" (well, what else?) - here is my version:

#include <Wire.h>

#define EEPROM_ADDR 0x50

char mymessage[6] = "HELLO!";
char readitnow = "";

void setup()
{
  Wire.begin();
  Serial.begin(9600);
  while (!Serial) {
    ;
  }

  Serial.println("Writing EEProm");
  Serial.println();
  delay(1500);

  writeonce();

  Serial.println();
  Serial.println();

  Serial.println("Reading EEProm");
  Serial.println();
  delay(1500);

  readonce();
}

void writeonce() {

  for (int i = 0; i < 6; i++) {
    i2c_eeprom_write_byte(EEPROM_ADDR, i, mymessage[i]);
    Serial.print("Address: ");
    Serial.print(i);
    Serial.print("   Value: ");
    Serial.println(mymessage[i]);
    delay(500);
  }
}

void readonce() {

  for (int i = 0; i < 6; i++) {
    readitnow = i2c_eeprom_read_byte(EEPROM_ADDR, i);
    Serial.print("Address: ");
    Serial.print(i);
    Serial.print("   Value: ");
    Serial.println(readitnow);
    delay(500);
  }
}


void loop()
{
}

void i2c_eeprom_write_byte( int deviceaddress, unsigned int eeaddress, byte data )
{
  int rdata = data;
  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddress >> 8));    // Address High Byte
  Wire.write((int)(eeaddress & 0xFF));  // Address Low Byte
  Wire.write(rdata);
  Wire.endTransmission();
}

byte i2c_eeprom_read_byte( int deviceaddress, unsigned int eeaddress )
{
  byte rdata = 0xFF;
  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddress >> 8));    // Address High Byte
  Wire.write((int)(eeaddress & 0xFF));  // Address Low Byte
  Wire.endTransmission();
  Wire.requestFrom(deviceaddress, 1);
  if (Wire.available()) rdata = Wire.read();
  return rdata;
}

Speaking (er, writing) of using an EEProm in a project, next week I think I'll look at using a small memory attiny chip to play some music using the external memory of this EEProm chip. Can't wait!


Monday, July 8, 2019

0000 0000 0000 0011

74HC595 Shift Register


My little friend the Attiny13 can count well, and the following code will output the numbers 0..255 
for (byte mynumber = 0; mynumber < 256; mynumber++) {
    displaynumber(mynumber);
    }
The problem with the output is that if we want to display the numbers using LEDs (well, who wouldn't), then we have a pin problem as a byte is 8 bits so 8 lights are needed. The Attiny13 has only 5 pins handy.


11 was a racehorse, 22 was 12, 1111 race 1 day and 22112

I'm definitely going to do some charlieplexing for that one in a future blog, but the vault reveals a 74HC595 shift register IC which happens to be great for extending the pins available.

There are thousands of tutorials on this chip out there on the interwebs, but I used this one when constructing the circuit and stealing writing the code.





0000 0000 0000 0010

ULN2803 Darlington Array

I would hate to count all of the transistors that I have purchased. Let's say more than hundreds! If you don't like collecting (a little joke) transistors then maybe this isn't the backwater of the internet for you.

Of all of the transistors in my collection, the SS8050 continues to be my favourite - but sometimes you need more power (mosfet?), and sometimes you might need extra goodies that make life easier for some applications.


So one of my "other" favourite transistors is actually an IC chock full of transistors called the ULN2803 - and it has some great features that make it a perfect choice when dealing with some situations such as large inductive loads (e.g. a motor), or maybe you just want to draw heaps of current in an easy "monolithic" way.


Let's say you have a motor kicking along at 12V and drawing 500mA current. Your microcontroller is going to spit the dummy real early for a couple of reasons. For instance the typical AVR (I use the Attiny13a way too much) cannot output that much current (40mA upper limit) from it's pins. Then when the motor stops and you get a bit of inductive kickback - the AVR could easily fry.


You can increase the current available by using a transistor as a switch and also you could protect your μC through the use of a flyback diode and all the other blah blah bits to make the circuit work OR you could just chuck a ULN2803 into your circuit which includes all the goodies shown in this block diagram as follows:

So many components for your viewing pleasure
The Darlington Pair at the heart of the block diagram (and remember there are 8 inputs and 8 corresponding outputs just like the one above on this single lovely chip) allows a total output current of 500mA. Because there are multiple inputs and outputs you can add as many inputs and outputs together as you need to get more current! Two inputs, parallel linked, gives 1A via parallel outputs, 3 gives 1.5A and so on. Need more power? No problem!

So the task for this week is to output some bulk mA and drive two 3W LEDs from a simple square wave generated by our "other other" favourite IC the 555 timer. As the timer kicks out a high, the 
ULN2803 should open the gate on heaps of current to simultaneously light the 3W LEDs enough to give us all a nice tan in the middle of winter.

The circuit is as follows:



The timer part - just providing a square wave out of Pin 3
More power on this side with the signal coming in to Pin 8

In real life
There are a couple of cute "gotchas" with this circuit. The first is that the positive or anode side of the LED connects directly to the "COM" pin on the ULN2803 and the ground lead plugs (via a resistor) into the "output" pin. You'd expect given the pins are called output that it would be the other way around.

The second is that those LEDs I've plugged in get pretty warm - it's OK for intermittent flashing but really they should have some form of heatsink if the current is large and constant.






Thursday, July 4, 2019

0000 0000 0000 0001

Introduction

Over the last three years I have overzealously bought a heap of electronic components for projects. Some projects have been finished (see the other blog for smatterings of these projects), but there are too many buckets of boxes of compartments filled with lovely OpAmps, Transistors, Logic Chips, Modules, Sensors and a multitude of other late night acquisitions which need to be used in some way.

They could sit and I guess I could be quite happy over the next few years admiring their dormancy OR I could get inspired and make one circuit a week to demonstrate their utility or otherwise.


Blog by blog I will attempt to document, video, draw, link, etc., each electronic creation in an effort to help me (and others) remember how to use some of this stuff (maybe to help prevent too much magic smoke escaping). I'm not an expert so if you spot anything that looks a bit dodgy - please let me know.


All of this work is also available on my youtube channel onecircuit.

I'll start next week - honest...



A small portion of the nonsense - ready to be used in this weekly blog!