Showing posts with label 16f877a. Show all posts
Showing posts with label 16f877a. Show all posts

Tuesday, December 13, 2011

Blood Bowl electronic board - slave board complete

Here's a quick update on our slave board for the Blood Bowl electronic board


The top board is underside of the slave board, which is basically a 40-pin 16F877A (any 40-pin PIC with hardware UART/USART would do, even the 18F4550 - but you'd be spending a lot more than necessary on your slave chip and not using most of the peripherals that you'd paid for! We just used one of the many 16F chips we had knocking around, not necessarily the cheapest/best fit for the job. One of the cheaper 16Fs from Farnell is the 16F1939 available for about �2.80 per unit)

The bottom board shows an arrangement of four 1x4 board modules (ok, it's actually 2 of our earlier 2x4 boards but the wiring is exactly the same!) We've wired them so that the two boards vertically share the same "row" signal wire. So both the boards on the left will come "live" at the same time, when row1 is sent high by the master board. Then the boards on the right will both come on at the same time. The two orange wires are the "row" signal wires and will connect to the master controller. The grey wires (to the left) will connect to the inputs on the slave controller.

Although not immediately obvious from the nasty photo (iPad cameras are about as good as cheap HP ones in low light) the slave board is simply a PIC microcontroller, a crystal, 4 wires (1 power, 1 ground, 1 serial TX, 1 serial trigger/handshaking line on the RX pin) and all the remaining digital i/o pins pulled to ground through some 100K SMT resistors.


Blood Bowl board game slave board

Our intelligent Blood Bowl game board consists of two PIC micros which talk to each other via serial (during testing we're using 9600 baud but will crank this up for the final version). The slave board is simply a 40-pin 16F877A with pull-down resistors on all the digital i/o pins.



To allow for maximum flexibility, we're designing this slave board to accept as wide a range of PIC microcontrollers as possible, including some of the 18F series chips (if you have some hanging around from other projects, why not use them instead of buying in new?) Allowing for the power, ground, TX and RX pins (which are in the same place in the 40-pin 16F and 18F chips), as well as the useless Vusb pin on the 18F (useless in this case since we can't use UART and USB together) and the handshaking line we've got a maximum of 30 input pins (we could use the RX pin for handshaking, but for now we'll keep that clear in case we can come up with a use for it in future). In the diagram above, all available i/o pins have been taken out to a set of SMT (1206 sized) resistor pads, and all the resistors are tied to ground (making them pull-down resistors on each input).

30 inputs is an awkward number to work with since each board module is 4 squares in size the maximum number of inputs we can use is 28 (4*7=28). So we've got two free input pins on the slave board should the need arise, as we develop the concept further.


Slave Board

Wednesday, November 30, 2011

Serial/UART communication between two PICs (18F and 16F)

It's taken a long time and a lot of different approaches to get even simple serial communication between two PICs working. Perhaps hampered a little by using two different PICs (a 16F and an 18F series chip) but that really shouldn't make any difference. Serial/UART communication shouldn't be platform dependent!

We've tried serial/UART, SPI, I2C and even bit-banging and each time got different (non-working) results. It's too much to go into in this blog post, so we're just going to describe how we actually got a working prototype:

The first thing to note is that although we're using one of our favoured 18F4550 PICs, we couldn't use the USB  and UART together. So for this experiment, we're reading the data back off our 18F (master) chip via serial, using the excellent PICKit2 programmer and software.

In our first (failed) attempt at creating pic-to-pic communication, we had our 16F (slave) device monitoring it's input pins and simply broadcasting the results as an 8-byte message over UART. The idea was for the 18F (master) chip to read this serial stream at intervals, find the start of the message and decode the rest of it, so that it knows the state of the slave chip.

In theory this sounds fine. In practice, sending more than about 4 bytes to the 18F (master) chip caused it to lock up on the Hserin command. We even tried connecting the PICKit2 to the RX pin on the 18F and removed our slave chip altogether. Our tests confirmed the same thing happening - if we sent one or two bytes at a time to the 18F from the PICKit2 terminal, it successfully received them and sent a response message back. If we sent more than about five bytes at a time, the 18F simply stopped responding - apparently locking up at the point where it reads in the serial data
(we proved this by switching an LED on just before the Hserin command, and turning it off again immediately after).

So it appears that we have a set-up whereby we can receive data from our slave, one byte at a time, but the master can't simply "dip in" to a serial stream being "broadcast" by the slave. After reading through the datasheet, it seems that the 18F has only a two (or was it four) byte buffer so blasting more bytes into the buffer than it can handle is causing some sort of buffer overrun error.

We need some way of getting the master chip to ask for data, one byte at a time.
This is what we came up with:

The master chip sends a pin high then requests a byte from the serial buffer.
The slave chip monitors the state of the "handshaking" line. When the line goes high, and the previous line state is low, this represents a request from the master, so send one byte.
Because we're using hardware UART on the master chip, after the line goes high, the code waits until a byte has arrived in the serial buffer. Because the slave only sends a byte on a low-to-high transition on the handshaking pin, we don't have to worry about buffer under-runs or errors in the master chip.



Slave code
'4Mhz external clock
Define CONF_WORD = 0x3f31
Define CLOCK_FREQUENCY = 4

AllDigital
Config PORTB = Input
Config PORTD = Input
Config PORTC = Input
Config PORTA = Input

declarations:
       Dim linestate As Bit
       Dim lastlinestate As Bit
     
       Dim a1 As Byte
       Dim a2 As Byte
       Dim a3 As Byte
       Dim a4 As Byte
       Dim a5 As Byte
       Dim xorval As Byte
       Dim bytecounter As Byte
            
init:
       WaitMs 50
       Hseropen 9600
       WaitMs 50
            
       linestate = 0
       lastlinestate = 0
       bytecounter = 1
     
loop:
       'all the slave does is read a whole load of input pins
       'and write the response back to the master. The master chip
       'will decide which "row" is live, this chip just takes all
       'the "column" data and sends it back to the master.
     
       'RA0-5
       'RB1-7
       'RC0-5 (6&7 are TX/RX)
       'RD0-7
       'RE0-2
            
       'this should give us 6+7+6+8+3 = 30 inputs
       a1 = PORTA And 63 '(mask off bits 7+6)
       a2 = PORTB And 254 '(make off bit 0, handshake line)
       a3 = PORTC And 63
       a4 = PORTD
       a5 = PORTE And 7
                   
       'now stream the values as a response back to the slave
       'all messages begin 255,255 (since this sequence is not
       'possible in the input stream because we bitmask bytes 1,3,5)
     
       linestate = PORTB.0
       If linestate = 1 And lastlinestate = 0 Then
              'the host chip has asked for another byte of data
            
              'create the checksum value
              xorval = 0
              xorval = xorval Xor a1
              xorval = xorval Xor a2
              xorval = xorval Xor a3
              xorval = xorval Xor a4
              xorval = xorval Xor a5
              xorval = xorval And 127

              'decide which byte of the message to send
              '(the host has to ask for each message eight times for all 8 bytes)
              Select Case bytecounter
                     Case 1
                     Hserout 255
                     Case 2
                     Hserout 255
                     Case 3
                     Hserout a1
                     Case 4
                     Hserout a2
                     Case 5
                     Hserout a3
                     Case 6
                     Hserout a4
                     Case 7
                     Hserout a5
                     Case 8
                     Hserout xorval
                     bytecounter = 0
              EndSelect
            
              bytecounter = bytecounter + 1
       Endif
       lastlinestate = linestate
     
Goto loop
End




Master code

AllDigital

declarations:
       Dim a1 As Byte
       Dim a2 As Byte
       Symbol lineshake = PORTA.0
       Config PORTA.0 = Output
     
init:
       Low PORTA.0
       WaitMs 200
       Hseropen 9600
       WaitMs 200
     
loop:

       Gosub getnextbyte
       'two 255 = start of message
       Hserout 255
       Hserout 255
       Hserout a1
            
Goto loop
End

getnextbyte:
       'to get the next byte, we send the lineshaking
       'line high - this tells the slave to "release"
       'another byte. Once we have this byte, we drive
       'the lineshaking pin low to say we're done
       High lineshake
       Hserin a1
       Low lineshake
     
Return


After connecting up the slave to the master (the TX pin of the slave into the RX pin of the master, and RA.0 on the master to RB.0 on the slave) we did actually start receiving intelligible data from the master. So it looks like we've (finally) cracked pic-to-pic communication over serial.

It's probably a bit slower than it needs to be (since the master has to "poll" each byte from the slave) but it's fast enough for what we want - and once we crank the baud rate up from 9600 to about 57600, or even 115200, it should be more than quick enough to scan an entire game board (of not more than 16 x 28 = 448 squares) at a reasonable rate.

Communication between two PIC microcontrollers

We're having a bit of a nightmare getting two PICs to talk to each other.
The master is an 18F4550 which will do most of the grunt work and talks to the PC host via USB (we use Oshonsoft's excellent USB/HID library for our USB work).

The slave is a 16F877A (no reason for this particular model other than we had quite a few of these lying around). This basic idea is that the 16F reads 28 input pins and writes a four-byte value out to the serial port.
The master periodically polls the slave, reading the serial data. It looks for two specific bytes which signify the start of the message, then reads in the next four bytes that make up the message (the fifth byte is the XOR sum of the previous four bytes so we have some sort of checksum).

The problem is that while we can check the 16F using the PICKit2 UART tool - and it successfully reads the message being "broadcast" by the slave - when we try to read data using the hardware UART port on the 18F master chip, the USB comms lock up and our PC app stops working.

It seems that we aren't the first people to run into this sort of problem and there are lots of queries across the 'net asking for help with USB and serial comms together. Here's just one example:


So it looks like USB and UART together isn't going to work.
Which is a bit of a bummer.
Also, like the author of the article above, we were also hoping to use the timer1 interrupt to keep a simple clock running, which makes software-based bit-banging and no-go either. Getting a PIC to work as an I2C slave looks quite complicated too, so we're running out of ideas.

The only thing left for us to try is getting two PICs talking to either other using SPI hardware on both the master and slave chips.

Hopefully this will work with both USB and timer1 interrupts running on the master chip. But until we try, we're not going to know......

PIC16F877A resetting

This is just a general post to remind anyone like me who often forgets the basics and spends far too long trying to find faults with hardware/firmware that just aren't there. Although in my case, it's specific to my 18F877A, the same rules apply to 16F628A chips and pretty much any of the 16F range.

Here's why I'm so stupid......
I've been working a lot lately with 18F series chips.
These are great because they have loads of different "fuses" which let you set up the chip in a particular way. One of the fuses on the 18F range allows you to reclaim pin one - the MCLR/PGV (programming voltage) pin and set it to an input. I do this with pretty much all my 18F chips.

So when I came back to the old 16F series chips (the 16F877A is an old favourite that first got me interested in PIC programming) I completely forgot that you need to apply 5v to the MCLR pin to stop the chip from resetting (pulling this pin low causes the PIC to reset completely).

So during testing, while trying to read the serial message(s) being "broadcast" from my 16F chip, I kept getting blackouts - periods when the serial stream would stop. Wiggle a few wires around on the breadboard and it would come back to life. For a little while.
Everything was pointing at a hardware problem - either a dodgy wire or a loose crystal or something. I re-wrote the firmware on both the slave and master chips, stripping each down to just the bare essentials, and used a really handy tool in the PICKit2 software to monitor the serial stream



You can connect anything that uses serial comms, and set the baud rate to any of the common bps values - 1200, 2400, 4800, 9600, 19200, 38400 etc as well as your own custom baud rate (ideal for debugging MIDI devices at 31250)


Anyway, after connecting everything up, setting it running and not touching a thing, the 16F would periodically shut down. I stripped out all the wires, rewired the board with a brand new set of jumper wires, put LEDs on all kinds of output pins and so on. I checked and double-checked the fuses, made sure the watchdog timer was disabled (and even tried enabling it and littering the firmware with watchdog reset commands) and checked the brown-out option wasn't selected. I even put a few different capacitors on the power rail of the 16F, just in case the input voltage was getting a bit wobbly.

The whole thing was suddenly a lot more complicated than any other PIC project I'd ever worked on and still it kept resetting.....

.... that's when I remembered that pin one (MCLR) has to be pulled high to stop the, erm, PIC from resetting all the time. Bugger.

It was as simple as that!
A single wire from pin one to 5V and everything worked beautifully.
If I had remembered about the MCLR pin earlier, instead of assuming it was always set to behave as an in input pin I think I'd have saved myself about two hours this evening.

Hopefully this post will help others in future to avoid wasting a similar amount of time on something so trivial!