This week's assignment was to program my echo board build in week 6. For this I started of reading the datasheet for 8 bit Atmel microcontroller.
I was unable to identify which all data from the datasheet I should be looking for. So I went through a couple of tutorials to figure out the basics of Embedded programming using C. Link to a tutorial.
With this I was able to understand the basics for programming in AVR-C. But that alone could not be useful without the my board design. Below is the schematic diagram of my echo board.
I identified the input port would be PORTB2 and output to be PORTA2 from my schematic diagram. I was able to write a couple of programs to blink the led on my board.
blink.c
#include < avr/io.h >
main(){
DDRA |= (1<<2);
DDRB &= (!(1<<2));
PORTB |= (1<<2);
while(1){
if(!(PINB & (1<<2))){
PORTA |= (1<<2);
}
else{
PORTA &= (!(1<<2));
}
}
}
I wanted to try out lighting led with a delay of 1 sec. Also I noted that the clock frequency for ATTiny44 is 20MHz from the datasheet.
delay.c
#include < avr/io.h >
#define F_CPU 20000000
#include < util/delay.h >
main() {
DDRA = 0xFF;
while(1) {
PORTA |= (1 << 2);
_delay_ms(1000);
PORTA &= (!(1<<2));
_delay_ms(1000);
}
return 0;
}
I tried out interrupts. My intention was to light the led on a delay, same as the above code, but also the light it, when I press down the button and go back to the delayed sequence when I let go on the switch. I used the following registers to
An interrupt vector is the memory address of an ISR, Interrupt Service Routine, and apart of the microcontroller's program memory. As such when utilizing interrupts this section of memory should be reserved to store pointers to interrupt handlers and not to store regular programs. The interrupt vector for each interrupt provided by ATtiny44 found from the datasheet.
interrupt.c
#include < avr/io.h >
#define F_CPU 20000000
#include < util/delay.h >
#include < avr/interrupt.h >
int pause = 0;
ISR(INT0_vect){
//interept service routine while interept is made by int0 pin
if (!(PINB&(1<<2))) { // if PB2 is low
pause = 1;
PORTA|=(1<<2); // set PA2 High
}
else{ // else
PORTA&=(!(1<<2)); // set PA2 Low
pause = 0;
}
}
main(){
DDRA=0xFF; // set PA0 to PA3 as output
DDRB=0x0; // set PORTB as input
PORTB|=(1<<2); // pullup PB2
pause = 0;
MCUCR = 1 << ISC00 ; // Any logical change on INT0 generates an interrupt request.
GIMSK|= (1 << INT0); // external pin interrupt is enabled on INT0 pin
sei(); // set global interrupt flag
while (1) {
// simply nothng
if (pause == 0) {
PORTA |= (1 << 2);
_delay_ms(1000);
PORTA &= (!(1<<2));
_delay_ms(1000);
}
}
return 0;
}
This above could works fine for interrupts duration lesser than 1 sec. But if I press on the switch more than that, it is found that the control doesnt seem to go back to the main program. That is, after a long interrupt, the delay sequence is not working. I accidently damaged my board, when trying to debug this issue.
Attached the Makefile I scraped from Neil's and accordingly change the name of the file you want to run. Run man avrdude
to access the manual for avrdude.
program-usbtiny-fuses: $(PROJECT).hex
avrdude -p t44 -P usb -c usbtiny -U lfuse:w:0x5E:m
The above was changed to the following, because the led was blinking rather fast. The delay was small. Found the lfuse setting was wrong.
program-usbtiny-fuses: $(PROJECT).hex
avrdude -p t44 -P usb -c usbtiny -U lfuse:w:0xDE:m
NodeMCU is an open source IoT platform. It includes firmware which runs on the ESP8266 Wi-Fi SoC from Espressif Systems, and hardware which is based on the ESP-12 module. The term "NodeMCU" by default refers to the firmware, which is written in Lua scripting language, rather than the dev kits.
I tried out blinking the LEDs available on NodeMCU and then ran the same again by hosting a server on NodeMCU and accessing a browser UI via the hotspot initiated from NodeMCU. I used MicroPython for setting up a socket connection on NodeMCU. The documentation for the steps carried out are provided below.
Datasheet for ESP8266
MicroPython
MicroPython includes the standard Python interpreter that runs on small embedded development boards. With MicroPython, you can write Python scripts to control hardware. For example, you can make LEDs blink, communicate with a temperature sensor, control motors and publish a sensor reading on the Internet. It is worth noting that the firmware for such embedded devices is generally coded in Assembly, C or C++, but using MicroPython you can achieve almost the same results as with high level Python. A detailed introduction to it is available on this link.
Setting up MicroPython on ESP8266 board
I followed this documentation.
I installed esptool and downloaded the bin file for the firmware. I downloaded the firmware from this link. Ran the following to setup micropython on the board.
pip install esptool
esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=detect 0 esp8266-20170108-v1.8.7.bin
I connected the board to my mac via the USB. I used screen to get a terminal window on my mac to a USB device or a serial device connected using a USB-to-Serial adapter. More details on this is available on this link.
I was able to access a new terminal within the board on my mac. This let me test out the modules available within the board by default. I can access it the same way I access python on my mac terminal. This link will give you some idea on what I'm refering. Details regarding the internal file system within the board. Even though Micropython have file editing capabilities, it was best use some sort of application that would let me transfer files into the board.
I used ampy which is a utility to interact with a MicroPython board over a serial connection. GitHub link to AMPY.
Some of the ampy commands I tried out
ampy --port /dev/tty.SLAB_USBtoUART get boot.py
ampy --port /dev/tty.SLAB_USBtoUART put boot.py
ampy --port /dev/tty.SLAB_USBtoUART put picoweb/__init__.py picoweb/__init__.py
ampy --port /dev/tty.SLAB_USBtoUART rmdir picoweb
ampy --port /dev/tty.SLAB_USBtoUART put picoweb
ampy --port /dev/tty.SLAB_USBtoUART ls picoweb
You might not see the rmdir
in the documentation of ampy. get
is to see the file in the board's directory on the terminal. put
is to overwrite the contents of the file or create a new file in the internal file system of the board.
By default there is a boot.py file which is the first python file that runs when powered up. After that main.py is run. So I decided to use boot.py and update the code there to try out socket connection.
socket.py
import machine
import gc
import webrepl
webrepl.start()
gc.collect()
pins = [machine.Pin(i, machine.Pin.IN) for i in (0, 2, 4, 5, 12, 13, 14, 15)]
html = """< ! DOCTYPE html>
< html>
< head> < title>ESP8266 Pins< /title> < /head>
< body> < h1>ESP8266 Pins< /h1>
< table border="1"> < tr>< th>Pin< /th>< th>Value< /th>< /tr> %s < /table>
< /body>
< /html>
"""
import socket
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
s = socket.socket()
s.bind(addr)
s.listen(1)
print('listening on', addr)
while True:
cl, addr = s.accept()
print('client connected from', addr)
cl_file = cl.makefile('rwb', 0)
while True:
line = cl_file.readline()
if not line or line == b'\r\n':
break
rows = ['< tr>< td>%s< /td>< td>%d< /td>< /tr>' % (str(p), p.value()) for p in pins]
response = html % '\n'.join(rows)
cl.send(response)
cl.close()
I then tried out implementing the same using a third party micropython web module called picoweb. My intention was to use picoweb to test out url redirection and templating of the browser UI. Importing picoweb on the screen terminal works fine. But certain modules within the picoweb keeps failing. I tried out multiple changes but none worked. I started finding some memory errors when importing picoweb. So I had to switch back to socket connection with no proper routing.
I build the code to blink based on the browser UI toggles, and blink it based on delay. I was still able to implement routing, but I'm not quiet satisfied by the capability of the routing mechanism I used.
delayblink.py
import machine
# import gc
# import webrepl
# webrepl.start()
# gc.collect()
html = """< !DOCTYPE html>
< html>
< head> < title>ESP8266< /title> < /head>
< body> < h1>ESP8266 - Micropython< /h1>
LED Pin 2
< a href="/led2/on">< button>LED ON< /button>< /a>
< a href="/led2/off">< button>LED OFF< /button>< br>< br>< /a>
LED Pin 16
< a href="/led16/on">< button>LED ON< /button>< /a>
< a href="/led16/off">< button>LED OFF< /button>< br>< br>< /a>
Delay Sequence
< a href="/led/delay">< button type="submit">Delay< /button>< /a>
< /body>
< /html>
"""
def SwitchON(pin):
pin.low()
def SwitchOFF(pin):
pin.high()
import socket
import time
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
s = socket.socket()
s.bind(addr)
s.listen(1)
pin2 = machine.Pin(2, machine.Pin.OUT)
pin16 = machine.Pin(16, machine.Pin.OUT)
print('listening on', addr)
while True:
conn, addr = s.accept()
print('client connected from', addr)
response = html
request = conn.recv(1024)
print(request)
if '/led2/on' in str(request):
SwitchON(pin2)
elif '/led2/off' in str(request):
SwitchOFF(pin2)
elif '/led16/on' in str(request):
SwitchON(pin16)
elif '/led16/off' in str(request):
SwitchOFF(pin16)
elif '/led/delay' in str(request):
seq = 10
while seq:
time.sleep(0.5)
SwitchON(pin2)
SwitchON(pin16)
time.sleep(0.5)
SwitchOFF(pin2)
SwitchOFF(pin16)
seq -= 1
else:
SwitchOFF(pin2)
SwitchOFF(pin16)
conn.send(response)
conn.close()
You can actually hear me clicking on the UI buttons :D . Tried out the buttons to light up the LEDs, then clicked Delay which lights up both LEDs and toggle simultaneously.