Thursday, 13 October 2016

CAN Bus Project Part 6 - The MCP2551

This is part 6 of my project to get my Arduino (/Genuino) and TI Launchpad to communicate via CAN.

Previously I've described getting my Arduino (/Genuino) to spit out CAN messages. Today I want to start talking about having the Launchpad receive them.

An Arduino/Genuino attempting to "talk CAN" faces two problems: Firstly, CAN is fairly complex; Trying to code all the CAN logic into an Arduino would be a hefty challenge. Second, even with the correct logic, an Arduino’s pins are physically incapable of generating the fancy ("dominant / recessive") voltages CAN needs.

Fortunately, the MCP2515 from Microchip solves both problems: Your Genuino talks to it (using SPI), and it translates your messages to CAN.

Unlike the Arduino, the Lauchpad comes with CANBus logic built-in (formally, it has 2 x CAN 2.0 A/B controllers) – so you don't need an external MCP2515 IC. 

In common with the Arduino however, the Lauchpad still can't generate the ("dominant/recessive") voltages CAN needs. So, whilst you don't need external CAN logic, you do need an IC to generate CAN voltages. A Microchip MCP2551 (High Speed CAN transceiver) is a suitable choice. It translates CAN voltage levels at its CANH / CANL pins into traditional "high/low” data on its RX pin.


An issue with using the MCP2515 is that it's a 5V device. Whilst this is o.k. for the Arduino, TI Launchpad pins are limited to 3.3V. It's common in electronics to need to shift the voltage level of signals and there're lots of solutions. I used an SN74LVC245A (Octal Bus Transceiver) IC to do the 3.3-to-5V conversion (mostly as I had one lying around).

To make it easy to connect things at the Launchpad-end of the CAN bus, I wire-wrapped the MCP2551, the SN74LVC245A, and some headers together on a vero-board – see photo. You can see one of the CAN termination resistors (explanation here) at the top of the frame.

If you've been following these posts, you'll know we now have all the hardware and Arduino sofware needed to bring a CAN message right up to the Launchpad pins. All that's needed now is to configure the internals of the Lauchpad... see you next time!

Wednesday, 12 October 2016

Embedded Basics No.1 - Registers

A core concept in embedded-electronics is the register.

For embedded newbies, put simply,

a register is a ‘box’ that stores a number

‘Stores’ means a register is a memory device. Place (embedded programmers say ‘poke’) a number into the ‘box’ (register), and it’s held there until you decide to change it or you power-off the IC.

Other parts of an electronic system may be able to read a number you’ve poked into a register, and adjust their behavior based on its value. Figure 1 shows the general idea. Here a 3-bit register controls 3 LED's. Poking the value '101' turns two LED's on, and poking '010', one LED.



Modern IC’s may contain hundreds of registers, each controlling a different feature of the device. Manufacturers therefore need to give you a way to single-out an individual register. They do this by giving each register a unique name or number termed its “address”. You use the address to send the IC instructions along the lines:

Hi Mr. IC, poke the value 17 to the register with address 82”

Hi Mr. IC, poke 23 to the register TXCTRL”

“Hi Mr. IC, what's the value in register RXBUFF?”

Here “TXCTRL” and “RXBUIFF” are  example register names (its traditional to use uppercase lettering for registers). 

The first two instructions are write-instructions. The third is a read-instruction. Not all registers allow both reads and writes. For example, a manufacturer might include a read-only register in an IC to store a serial number, giving you the ability to read the number, but not over-write it.

Some registers contain both write’able and read-only regions. For example, a register might store an 8-digit (bit) number, but only allow you to write (change) seven of these bits, the eighth bit being permanently fixed (at ‘1’ say). 

It can also be important to know what value may be present in a register before you write anything to it (the default value present in the register immediately after you’ve powered-up the chip for example). 

All the various properties of an chip's registers are stated in the datasheet in a (fairly) standard format. Figure 2 shows a typical (fictitious) example.



In words, the table can be understood as saying:
  • CFG0 is the name of a register name with address "127" (= 7F in hex)

  • The register stores an 8-bit (binary) value. The individual bits are themselves named (LED0, LED1...CTRL).

  • Bits 0 - 4 can be both written (‘W’) and read (‘R’).  

  • Bit 5 - 6 can be read, but not written (changed).

  • Bit 7 can be written but not read.

  • Bits 1,2,3,5,6 have default value '0' 

  • Bits 0,4 have default value '1' 

  • Bit 7  has an undefined ('U') default value
In addition to the table, the datasheet will describe what each section of the register does. For example the datasheet might describe the function of the 'LED0' bit by saying

  • LED0: Writing '1'('0') turns the on-board LED#1 on (off)


(By the way, precisely how you send register-read/write instructions to a chip depends on the device. For some, you might send instructions via an (e.g. SPI or I2C) interface; A microprocessor might have the instruction written into its software. Written in C (you can skip this bit if you don’t know C, but you should be aware that a large proportion of embedded software uses it), the second example instruction above might look something like

*(TXCTRL) = 23

I should add there's a lot more could be said here about pointers, volatiles etc.  but these are software topics for another time).

Finally, at the hardware level, a register is typically just a row of (one or more) edge-triggered D-type flip flops. Unless you’re heavily into transistor-level integrated-circuit design, it’s rarely necessary to understand the inner workings of flip flops, so I won’t get into details here. Wikipedia is the place to start if you’re hungry for more. It’s enough to know that a ‘1’ (or a ‘0’) put on the ‘D’ input of a flip-flop, will be captured and stored if a rising-edge (a voltage step) is applied the ‘Clk’ input. The stored ‘1’ (or ‘0’) will show up on the flip-flop's ‘Q’ output. A row of D-type flip flops allows you store a set of '0’s and ‘1’s – in other words it forms a register.

The ability to arrange and manipulate registers is so important in digital system design (for example, when creating ASIC's or programming FPGA’s) that dedicated hardware design languages (HDL’s) such as VHDL and Verilog are available to help streamline the task. In a language like VHDL, you routinely see lines of code like

If rising_edge(clock) then A <= “10101010”; 

This translates as an instruction to your FPGA / ASIC design- tools that you want a (clocked) register with an output called “A”, storing the value “10101010”.

I’ll end my brief introduction to registers here.

Do drop me a comment on this, or any of the others topics on this blog.

Monday, 10 October 2016

PCB Design Tips 2 - Surface Mount Breakout Boards

A challenge we electronics hobbyists face today is the growth of surface-mount packaging.

Once upon a time, IC's came in nice chunky DIP packages, with legs perfect for slotting into your breadboard. 

Sadly those days are gone :-(  

Demand for ever-smaller, ever-lighter electronic gadgets has driven the electronics industry to adopt surface-mount packaging. For a while, many IC's were available in both DIP and surface-mount packages, but a growing numbers of chips are available surface-mount only.

Of course, reflow ovens offer a route for the hobbyist to prepare surface-mount boards, but there are days when you just want a quick-and-dirty way to hook up that surface-mount IC.

One approach to rapid prototyping I've recently enjoyed some success with is breakout boards. These give you a pattern of solder pads, routed-out to a series of (plated) holes into which you can solder connector-wires. 

The photo shows some from Adafruit (I've no connection to the company) I picked up off eBay recently for a couple of quid (that's "bucks" to my US readers). 




These particular boards are double-sided, with an SOIC-8 (=1.27mm pad pitch) pattern on the front and an MSOP-8 (=0.65mm pitch) footprint on the back. 

Five minutes with my soldering iron, and I had my chip down.




A few minutes later, I'd some flying-wires attached, and was all ready to plug the chip into my breadboard. 




As for identity of the chip itself...well, that's another story for another day.

Sunday, 9 October 2016

Introducing the Tiva Lauchpad

Everyone knows the Arduino (/Genuino), but some may less familiar with the Texas Instruments Tiva LaunchPad.  

I’m planning to use this in some future posts, so today is a quick intro. to this nifty little board. All views here are my own by the way - I'm not paid to give them!


The Launchpad is one of a bunch of low-cost boards built around ARM microcontrollers. Others include the Nucleo and boards by RedBear.

Working with these boards is similar to working with the Genuino. You write code on your PC and download it to the board via USB. 

What the Launchpad (full name Tiva-C TM4C123 Launchpad) gives you compared to the Arduino is much-increased processing power and added features.   

On the hardware side, for less than $20, you get an 80MHz ARM M4 processor; 256K of flash memory; a 12-bit ADC; multiple (USB, I2C, SPI, UART and CAN) interfaces;  43 GPIO’s; and several others features including PWM, Comparator and DMA modules. The board doesn't have wireless or ethernet, but there're still plenty of projects you can do without these. (Other boards in the Tiva series do have wireless connectivity - I'll take about these another time).

On the software side the Launchpad is a great way to grow your embedded skills. At first, you might choose to program it using the quick-and-easy Energia software environment. This makes writing Tiva software look-and-feel like Arduino code.  Or you might download Texas Instruments’ (free) Code Composer Studio environment. This comes with ready-made C-code examples (an API) that help you access the Lauchpad's features.  Ultimately you can move on to advanced embedded software techniques such as RTOS programming and the ARM CMSIS.

All round, the Launchpad is great value and has enough power to deliver serious results. It's something I'll be using frequently in future posts.

Friday, 7 October 2016

PCB Design Tips No.1 : Stake It !

I'm taking a break from my CAN project today to post the first in series of PCB Design Tips.

As electronics junkies we've all encountered some pretty dreadful circuit boards:

Maybe it’s the unsafe mess you discover when you take the lid off that bargain-basement battery charger. Or maybe you're the one slopping solder around on a quick-and-dirty proto-board.

Every now and again however, you need things done right. Whether it's a PCB you're putting into production or your high school battlebot's motherboard, sometimes you need a board that's built-to-last. 


If you want to discover how to put together a top-notch PCB, then quality doesn't come higher than Space Grade.

 PCB's for space missions must withstand extremes of vibration, temperature and radiation. And they must not fail: Getting the soldering iron out to re-attach a loose wire isn't an option when your board's half way to Jupiter! 

Space agencies like NASA and ESA publish strict rules on PCB build-quality.  Example document numbers to google are NASA-STD-8739.1B and ECSS-Q-ST-70-08C. Of course, no one's saying your one-dollar widget needs ultra-precision, but a quick skim through rules written by the experts can be a great source of tips for improving your PCB designs.


Take flying-leads (wires from your board to a connector, say). The rookie approach might be to dab a bit of solder onto the lead ends, and finish there.

That's not the way the professionals do it (see figure). In addition to being soldered to the board, space engineers make sure the lead goes a second hole where its staked ('glued'). 

The space-quality rules also tell you that bends in the wire mustn't have a radius of less than 2x the diameter of the wire; that soldered ends of wires must protrude 1.5mm through the board; and that insulation must be stripped back 1-2mm from the point where wires meet the board. 

Staking glues are carefully chosen also. A blob from a hot-glue-gun may be o.k. for a hobby-board, but for PCB's to stand up to serious vibration, you need a glue with enough elasticity (the technical term is a low modulus) to 'soak up' stresses. Specialist epoxy resins like Scotchweld 2216 (I've no connection to the company - this isn't a plug!) are common in the industry. At $20'ish-a-tube, it isn't cheap, but it could be a lot cheaper than putting that failed board in the bin.

So there you have it - next time you need a board that's built-to-last, take a tip from the experts: Stake It! 

I'm always delighted to get any feedback on these posts, so do leave a comment... 

Tuesday, 4 October 2016

CAN Bus Project part 5: Arduino Sketch

This is part 5 in my project to link my Arduino to a Texas Instruments Launchpad using CAN.

Below is my code to link an Arduino to a Microchip MCP2515 CAN chip. (I've put the code on my gitHub also). It builds on the code in previous posts. Its function is to grab a temperature off the thermistor I described in part 2, and shove the value out on the CAN Bus.

I'm not going to talk through every line of the code here. The basic flow follows the "Transmit Message Flowchart" in the MCP2515 datasheet. I've added plenty of comments, so it shouldn't be too hard to follow.  For those of you  totally unfamiliar with embedded coding, I may post a basic introduction to some of the standard coding practices (how to set/clear bits in a register etc.) at some point.

Next time I'll move on from the Arduino and start talking about the other end of the link: The Tiva Launchpad.


/* VoltageBias - the Blog * Gilbert Waltoon
*
* Released under a GNU General Public License v3.0
*
* FILENAME : ARDUINO_MCP2515_CANBus_TX
*
* PURPOSE : Sends temperature data from Arduino Uno via CANBus.
* Uses Microchip MCP2515 CAN transceiver IC.
* See VoltageBias - the blog, for full details.
*
* Arduino hook-up guide:
* SPI CS : Uno pin 7 (selectable) - see file MCP2515_Registers.h
* SPI MOSI: Uno pin 11
* SPI MISO: Uno pin 12
* SPI SCK: Uno pin 13
* Power rail etting : 5V
*
* ******************************************************************
SETTINGS - Change me!!!!!
*/
#define RESET_ON_RESTART (true) // Reset MCP2515 when Sketch restarts
#define CNF1_TIMING (0x01) // Using 8MHz-Xtal on NiREN board so
#define CNF2_TIMING (0x9A) // set MCP2515 CAN timing registers
#define CNF3_TIMING (0x07) // accordingly.
//See https://www.kvaser.com/support/calculators/bit-timing-calculator/
// **********************************************************************
// Globals and Includes
#include <SPI.h>
#include "MCP2515_Registers.h"
#include "Thermistor_helper.h"
int msgData =0; // will contain the message data to be transmitted.
int msgSID =0; // will contain CAN-message identifiers.
// *******************************************************
// Sketch setup...
void setup() {
pinMode(chipSelectPin, OUTPUT);
//Start the Serial monitor
Serial.begin(9600);
//I nitialise the SPI link to thr MCP2515
SPI.begin();
SPI.beginTransaction(SPISettings(1400000, MSBFIRST, SPI_MODE0));
/*
140 000 000 here gives Sck period c.120ns i.e. 8MHz
14 000 000 gives Sck 1us i.e. 1MHz
SPI_MODE0 corresponds to CPOL 0, CPHA 0
SPI_MODE1 corresponds to CPOL 0, CPHA 1
*/
if (RESET_ON_RESTART) {
Serial.println("Resetting");
resetIns(); //call reset function (see MCP2515_Registers.h)
}
// Enter MCP2515 configuration mode using setMode()
// function defined in MCP2515_Registers.h,
// and set up CAN bit timing registers.
while ( !setMode("Configuration") ) {};
writeIns(CNF1, CNF1_TIMING);
writeIns(CNF2, CNF2_TIMING);
writeIns(CNF3, CNF3_TIMING);
// Bit timing registers above are write-protected
// outside of 'Configuration' mode so, for safety,
// check they were successfully modified
while ( readIns(CNF1) != CNF1_TIMING ) {
Serial.println("Failed to write to CNF1");
delay(999999);
}
while ( readIns(CNF2) != CNF2_TIMING ) {
Serial.println("Failed to write to CNF2");
delay(999999);
}
while ( readIns(CNF2) != CNF2_TIMING ) {
Serial.println("Failed to write to CNF3");
delay(999999);
}
// Set MCP2515 mode to normal operation
while ( !setMode("Normal") ) {};
// Abort any pending transmissions
// by setting the ABAT bit of the CANCTL register
bitModifyIns(CANCTRL, ABAT, ABAT);
// Clear the abort-transmission instruction above
bitModifyIns(CANCTRL, ABAT, 0b00000000);
//Load TXB0SIDH transmission register with 0's
ldTxBuffIns(LD_TXB0SIDH_INS, 0x0);
//Set CAN frames as Data frames of 1 byte by
//configuring TXB0DLC register.
writeIns(TXB0DLC, readIns(TXB0DLC) & (~RTR) & (~DLC3) &
(~DLC2) & (~DLC1) | DLC0 );
//Don't trigger interrupts upon transmission
bitModifyIns(CANINTE, TX0IE, ~TX0IE);
//Configure RXB0 receiver to accept al1 messages
bitModifyIns(RXB0CTRL, RXM1 | RXM0, RXM1 | RXM0);
//Don't use pins for interrupts
bitModifyIns(BFPCTRL, B0BFM, ~B0BFM);
//Don't use RX interrupts
bitModifyIns(CANINTE, RX0IE, ~RX0IE);
//Clear any 'RXBuffer full' interrupts
bitModifyIns(CANINTF, RX0IF, ~RX0IF);
Serial.println("Completed setup");
Serial.println("***************");
Serial.println();
}
// end of setup()
// **********************************************
// *********************************************
// Main Sketch loop...
void loop() {
//get some temperature data to act as message data
msgData = getThermistorTemperature();
//Load TXB0 buffer with message data
ldTxBuffIns(LD_TXB0D0_INS, msgData);
// Set CAN message ID to value of msgData,
// and set EIXDE = 0 (=standard, non-extended, identifer)
writeIns(TXB0SIDL, ( readIns(TXB0SIDL) & (~EXIDE) & (~SID0) &
(~SID1) & (~SID2) ) | (msgSID << 5) );
//Request TXB0 CAN buffer to send its data
rqstToSendIns(RTS_T0_INS);
//Print some status info. to the serial monitor
Serial.print("Sending temperature="); Serial.print(msgData);
Serial.print("\t"); Serial.print("With SID=");
Serial.println(msgSID);
//wait for message to go
delay(100);
// call check4Errs() (see Registers.h)
// to print any errors on serial monitor.
check4Errs();
//increment the message ID
msgSID = (msgSID + 1) % 8;
//wait a bit, then loop.
delay(2000);
}
// END
// *************************