- When given 5V, it shows live date, time, day and temperature
- When no power, it runs on battery - no display but timekeeping continues
- When there is an event, it shows ‘Happy Birthday/Anniversary’ message
- It can be programmed with new code e.g. updating events
- From an event, you can go back to normal display by pressing a button
- You can update date/time/day using buttons
- cxem - RTC using ZS-042 module. In Russian but simple with photos and code
- video - RTC using Arduino but helpful hints on basics
- Vcc (2.3-5.5v, typ 3.3v), logic 1 (0.7*Vcc-Vcc+0.3), logic 0 (-0.3-0.3*Vcc)
- BCD - Most values are stored in this format
- 2's complement - temperature is stored in this format
- positive number, no change (same as binary),
- negative number, invert & add 1
- if 8 bit can store 0-255, in 2's complement form, it will store -128 to +127
- Pull-up resistors 4.7k on each SDA/SDL/32K/INT lines, reset does not need an external pull-up (has an internal 50k ohm pull-up)
- ZS-042 module has all these pull-ups (4.7k), no need for external resistors
- Same i2c interface pins can be used for both DS3231 and eeprom (the two chips present on ZS-042)
Notes on I2C
- SDA/SCL pins in I2C are Open-drain pins. Connect to 5V via pull up resistors
- SDA/SCL pins in atmega328 have internal pull-ups also available. Not used but some information
- SCL frequency = f_cpu / (16 + (2*TWBR*Prescalar)). Tried speeds 100-400 KHz - all worked. Settled on 200 KHz. Display is refreshing fine every second
- AVR cpu speed to be increased from 1MHz (projects so far) to achieve the minimum (100khz SCL frequency). Increased default 1 MHz to 8MHz by removing clock division by 8. For this low fuse byte changed - bit 7 changed from 0 (programmed) to 1 (unprogrammed).
It is necessary to define F_CPU in makefile because clock speed is needed at compile time. Adding F_CPU definition in C file/.H file did not work.
- Lcd is very useful in i2c debugging since many intermediate statuses/ACK/register values are to be printed.
- Printing register values in 8-bit binary format is very useful on LCD. First line on LCD : name of register and expected value, 2nd line : actual value. Added function printregister() in lcd.h to do this printing.
- io.h having I2C registers values etc. Link
- I2C status codes - names and hex values. Link
- To send data on I2C, setting start bit separately first and then setting TWINT and TWEN does not work - all 3 have to be done together!
- Do we need to enable 'twen' every time we set 'twint' to 1? YES!
- Why twen bit has to be set everytime
- when twint is 0, system is doing something (transmission)
- when twint is 1, system has completed transmission & is waiting for you.
- You do something (eg. load data to send) & write twint to 1 (this is weird but it is like this)
- TWIE bit is to remain 0 as we are polling (page 225)
Most used registers (useful link)
TWCR TWINT | TWEA | TWSTA | TWSTO | TWWC | TWEN | - | TWIE
(interrupt flag | enable ack bit | start | stop | write collision flag | twi enable|-| twi interrupt enable)
TWDR to send/receive data or memory location
TWBR to set bit rate; SCL freq = CPU clock freq / (16 + 2 * prescalar * TWBR)
// Prescalar = 1, TWBR = 32, CPU clock 8 MHz, SCL freq = 100 KHz
TWSR will have status information after every operation [in bits 3-7, bits 0-1 are for pre-scalar; bit 2 is not used]. Status can be from peripheral (RTC or simply result of an operation eg. START sent successfully)
Transmission statuses in master transmitter (MT) mode
0x08 - Start transmitted - TW_START
I2C (TWI) steps (summary link)
To write to ds3231
- send start
- send slave device address (for RTC 1101000) + '0' for write
- receive ack 0
- memory location address (where to write) [00h-12h timekeeping registers of RTC]
- receive ack 0
- send data byte
- receive ack 0
- send data byte
- receive ack 0
- send stop
To read from ds3231
- send start
- send slave device address
- send 0 for write
- receive ack 0
- memory location address (where to read from) [00h-12h timekeeping registers of RTC]
- receive ack 0
- send repeat start
- receive ack 0
- send slave device address + '1' for read
- receive ack 0
- read data byte
- send ack 0
- read data byte
- send ack 0
- read data byte
- send nack 1
- send stop
Tests
- read all RTC values (one by one)
- read in quick succession to see seconds/minutes working
- read continuous memory locations (auto append of memory location)
- BCD to decimal/binary conversion (bit shift)
- decimal/binary to hex/ascii char conversion (+48)
Program logic for basic read/write
start
sla+w
first memory location 00h
set all rtc values starting from 00h (auto append of memory location pointer 00h-05h)
//while loop start - for continuous clock
repeat start
sla+w
memory location reset - 00h
repeat start
sla+r
read all rtc values - starting from 00h (auto append happens for memory location pointer 00h-05h)
print rtc buffer
delay 1ms
// while loop end
User interface - buttons
- Added 4 buttons to update date/time at microcontroller GPIO pins: setup (normal button - self locking), mode, + and - (3 push buttons)
- To add a button in atmega gpio pin - default is high (connected to 5V via a pull-up resistor), pulled low when pressed (push button connects to ground)
- GPIO pins pullup resistor value - 20-50k as per datasheet, used 39k on Breadboard and 47k on PCB
Overall program flow (final)
Setup atmega pins data direction for buttons
Initialise LCD
Set I2c speed
Check if RTC is at factory default, if yes, set date/time as per system*
Continuous loop 1 starts
Read live values (date/time/temperature) from RTC and display on LCD
If 'setup' button is pressed, continuous loop 2 starts
>show default mode ie current year on LCD
>user can press mode button to change to other modes ie current month,
date, day, hour, minute
>+/- buttons are used to change a value
>press 'setup' button again to save changes and exit
Continuous loop 2 end
If current date matches one of the event dates (birthday/anniversary), show ‘happy <event>’ on LCD
>to go back to normal display, press 'mode' button
Continuous loop 1 end
* Getting date and time from system, __DATE__ & __TIME__ functions in gcc. Conversion of formats
Battery
- Tested zs-042 with battery. It works on battery when Vcc is switched off
- RTC value does not change on make flash/reset button.
- To revert RTC to factory default, remove battery and switch off power
- CS2032 (non rechargeable) 225 mAH - readily available and cheap. Life can be 5-10 years based on RTC requirement of 3.5 uA (max) - not tested
- LIR2032 (rechargeable) 50 mAH - not readily available
- Useful links:
- Detailed analysis link at ganssle
- Stackexchange
- Arduino forum 1
- Arduino forum 2
- Details of zs-042 - including the eeprom and the battery
Breadboard
Kicad Eeschema
Kicad steps
- Page properties update
- Add key components (symbols)
- Add connector wires (most easy first)
- Add not connected symbol where needed
- Add small components like resistors, capacitors, switches etc
- Add power and ground symbols
- For neatness:
- Update symbols to rearrange pins if needed (right click, properties->edit with lib editor)
- Place properly with distance, move around component, label, reference value
- Connect components without wires if neat (using net labels) ex. exposing all atmega pins via connector
- Check all power input pins are marked so in various components
- Make all power output pins as passive if marked as ‘power output’ in component symbols
- Add power flags to power sources
- One each in all positive terminals
- One to ground
- Annotate
- Run ERC
Settings to update in pcbnew
Spec name (lion) | Specs (lioncircuits) | Actual used | Kicad setting |
Minimum Board Dimension | 3mm * 3mm | ||
Copper weight | 1 oz (35um), 2 oz (70um) | 1 oz | |
Board (PCB) thickness | 1.6 mm | 1.6 mm | Layers setup |
Board (PCB) Finish | HASL | ||
Minimum trace width | 6 mil | 10 mil 30 mil for power | Design rules |
Annular ring thickness | 6 mil | manual chk | Pad properties |
Minimum trace spacing (clearance) | 6 mil | 12 mil | Design rules |
Trace and Copper pour distance (clearance) | 8 mil | 12 mil | |
Between vias distance (clearance) | 12 mil | 12 mil | |
Via and trace distance (clearance) | 12 mil | 12 mil | |
Circuit to edge | 12 mil | manual chk | |
Silkscreen and solder pad distance | 6 mil | manual chk | |
Solder mask dam width (min solder mask width) | 6 mil | 6 mil | Pads mask clearance |
Solder mask clearance after pad | 2 mil | Pads mask clearance | |
Drill hole diameter | 14 - 248 mil | via dia 30 mil via drill 15 mil | Design rules |
Silkscreen minimum text height | 23 mil | manual chk | |
Silkscreen minimum text width | 6 mil | manual chk |
Other notes
- Grid resolution while creating
- schematic 10 mil
- pcb layout 50 mil
- trace drawing 10 mil
- Courtyard layer specifies the minimum distance a component needs before another starts
- Settings —> setup; Load netlist after completing settings
- Boundary —> edge cuts layer, draw using lines, thickness 0.001, set grid to 10 mil - these are final board dimensions and are related to cost, matching LCD dimensions (80 * 35 mm) to begin with
- Layer selection each time: select FCu (Front copper) now
- To layer LCD on top of main PCB - position of first pin and mounting hole to be carefully calculated from edge of PCB
- While making tracks change the grid to 0.1 mm for better bends
- Tried ways to fit 14 tracks between uC and pin socket: track width - tried 6 mil, 8 mil, 9 mil - all 3 can go through uC/pin socket pins, 10 mil cannot - although distance b/w pins is 13 mil ((2.54mm-0.8*2mm)-12*2mil)!
- Pin socket footprint to be updated - pins in sequence w.r.t uC, silkscreen etc.
- Bottom silkscreen display mirrored, text name of board, width and height 0.1”, thickness 0.02"
- For ground pour, place zone on both top & bottom layers, outside boundary
- If needed (by some fabrication service), file extensions may be changed:
- .gm1 —> .gko (no need to do this for LionCircuits)
- .drl —> .drd (no need to do this for LionCircuits)
- Gerbers:
- File—>Plot. Lion circuits link on how to generate gerbers
- Check generated files by opening in Gerbview: load drill first (File->Open Excellon Drill files), then all others by multiple selection (File->Open Gerber Files). Check each by selecting just that one
Printed PCB (from lioncircuits)
SMD soldering experience
Reflow soldering with solder paste
- 1st attempt: silicon mat burnt at ~160-180*C, solder was good
- 2nd attempt: bigger pan blackened from 2 spots at 160*C, base became uneven, board burnt from 1 corner (small)
- 3rd attempt: smaller pan burnt (from almost all over) at 160*C, board burnt further from 2 places (copper visible from one place)
- 4th attempt: bigger pan at 180*C, board burnt further from 2-3 places
- By DD ElectroTech
- By Param Aggarwal
- By Hobbytronics101
- By Sparkfun (read user comments too)
- Apply solder paste on pads and place DS3231 SMD chip using a tweezer. Link for solder paste used.
- Sand in pan with temperature probe. Switch on gas on highest setting. Reach 250*C
- At 250*C, place pcb (on silver foil) on sand. Cover. Place probe in sand through hole in cover. Gas burner remains on at high.
- Start watching carefully. At 300*C, switch off gas
- Keep watching carefully. Solder should start melting at anytime between 1 to 5 minutes after placing the PCB
- When reflow happens, solder becomes shiny and flows on pads properly
- Remove cover, using a spatula and spoon remove PCB (with foil) and place to cool
Use solder wick to clean bridges (if any)
Through hole (THT) soldering experience
- Put paper tape on loose components to hold them. Then solder from other side. Tape ensures components stay flush on board
- Solder front side components (buttons specially the big one) and berg strip only after LCD to avoid uneven board surface right in the beginning
- Solder LCD pins to board first, then pins to LCD!
- Soldering order:
- Bulk (including atmega, resistors, capacitors etc.)
- Battery holder, barrel jack, lcd pins to board
- LCD
- Front buttons and berg strip
- Big button
- Clean with 99.9% Isopropyl alcohol and an old soft bristled toothbrush
- In hindsight - Should have put hot glue in between the pub and lcd (when lcd is pressed , it restarts - may be making some unwanted connections)
Software error while pushing code to Happy Hour (due to recent macOS upgrade to Catalina)
- Sort out the shell
- chsh -s /bin/zsh : this changed the shell to zsh (default in catalina)
- nano .zshrc, update path e.g. export PATH=" "
- Ctrl+O (to save), Return to confirm file, Ctrl+X to exit
- . ~/.zshrc to activate
- echo $PATH to double check
- This changes the path for all sessions
- AVRdude v6.0.3 not working (Bad CPU in executable)
- Downloaded latest v6.3 from here
- Installed in /usr/local/avrdude-6.3
- How to update
- Steps to get it working from official pdf
- $ cd avrdude-6.3
- $ ./configure
- $ make
- $ su root -c ’make install’
- No USB support error
- Downloaded latest libusb v1.0.23 from here
- Copied (libusb-1.0\libusb.h) in AVRdude folder (/usr/local/avrdude-6.3)
- Compiled AVRdude again (above 4 steps)
- Downloaded latest version of AVR tool chain (libc v2.0.0/ gcc v9.3.0/ binutils v2.3.4/ gdb v8.3.1) from here
Program not flashing in one of the happy hour boards
Next steps: to de-solder LCD, ATMega, replace ATMega, re-solder
Link to code
Link to previous project: LCD
Link to previous project: Good Listener
- I2C steps are valid. Difference from DS3231 I2C transmission:
- Current address read ability
- Two bytes address (instead of 1) 12 bits needed for 4096 bytes
- Writing to be done 'page' by 'page' (32 bytes), explicit rollover required. Not required for 'read'.
- Special case may be required for 'last' page
- Device address is 1010111 (last 3 digits A0A1A2 are 111 instead of 000)
- System hangs if you send i2c read/write without stop. this was not the case with rtc.
- write & read one byte - did not work initially because of no delay between write and read. Datasheet recommends 10 ms delay. Working with 2 ms.
- write & read one page (32 bytes)
- write & read 2/2+/3 pages (rollover across pages)
- write & read last 2-3 pages (rollover across last memory location and first - loop - overwrite first page)
- read from file - ability to change start memory location