Pages

Wednesday, April 18, 2012

Fixing bad fuse settings on Atmega328 with AVR Dragon

Once in a blue moon as I try to program an ATmega328 with an AVR Dragon, I will get an 'ISP Mode Error' message. Somehow, clock select fuse (SUT_CKSEL) changes from internal 8MHz oscillator to an external crystal (which my prototype circuit does not have), hence making ISP not work. I said somehow because I am not sure what is going on since I did not change the fuses intentionally. Guessing the circuit and the mess of jumper wires on the breadboard cause havoc.

Luckly, it is easy to 'un-brick' the chip by using Dragon's parallel programming. It's just annoying to get the ISP Mode Error and having to set up jumpers for the parallel programming. I should just make a little board with headers - but not now! In order to parallel program ATmega328, wire the chip to Dragon as shown on the Dragon Online Help:
After setting it up for parallel programming, connect to AVR Dragon with AVR Studio (I am using version 4.18) select 'PP/HVSP  Mode' from 'Programming Mode and Target Settings under Main tab. Then click on the fuses tab and set the fuses accordingly, and click program.



You can program a variety of AVR microcontrollers with Dragon and you can find default values of the fuses for your chip here.

If you don't have a dragon but an Arduino, you can use High Voltage Programmer shield. I don't know how good it is since I don't have one and haven't played with Arduino that much yet. But sounds like a cool project to mess around with.



Friday, April 13, 2012

Simple Serial Port Monitor in C#.NET

This is an application that I wrote in C#.NET (3.5, VS 2008) in order to interface AVR microcontroller with a PC over the serial port.  I wrote this app as an exercise and to have something available that I can easily modify and extend for different projects and requirements.  I've also included numerous links and references to information on serial ports and many serial port communication example codes.

First, let's create a Windows Form for our GUI. ComboBox'es to input serial port configuration values, Buttons to open, close port and send characters out, TextBox to type in characters to be sent, a RichTextBox as a display. Nothing to it really. Naming convention for the controls are ComboBoxes as cbPortName, cbDataBits, etc., Buttons as btnOpenPort, btnSend, TextBox as txtSend, and richTextBox as rtbDisplay

This example makes use of the SerialPort class available in .NET. SerialPort class was introduced with .NET 2.0 and consequent .NET versions provided improved functionality. System.IO.Ports namespace must be included in order to use this class.

Code:

Create an instance of the SerialPort class and attach an event handler for the DataReceived event. I populated the combo boxes manually during design time, except for port names and parity values. Used the GetPortNames() static method to get the available COM ports in system. (Then an if statement to set COM1 as default since it is the one I am using and don't want to click it everytime the program runs.) SerialPort also has StopBits property which can be used to populate cbStopBits combo box at runtime but it has a bug: One of its values is None (StopBits.None. if selected it will throw an ArgumentOutOfRange Exception) Hence, I choose to add most combo box items manually during design time in Visual Studio.



RichTextBox control provides advanced formatting features. One of which selecting the text color. Using the SelectionColor property to assign different font colors for TX, RX and Error types makes it a bit more visually pleasing.

Another thing to note is that you cannot simply update the rtbDisplay control as rtbDisplay.AppendText(port.ReadExisting());. This is because DataReceived and the Form control are running on different threads and access to Windows Forms controls is not inherently thread safe; you will receive a Cross-thread operation not valid error. ( How to: Make Thread-Safe Calls to Windows Forms Controls) That's why we used the Invoke method.

This is just a quick and dirty program to communicate with the serial port. It could use some improvements such as using try/catch blocks to handle errors more gracefully, a Text/Hex option, file sending option etc., but this should get us started.

using System;
//using System.Collections.Generic;
using System.ComponentModel;
//using System.Data;
using System.Drawing;
//using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using System.IO;

using SerialPortMonitorApp;

namespace SerialPortMonitorApp
{
  public partial class Form1 : Form
  {
      SerialPort port = new SerialPort();

      public Form1()
      {
          InitializeComponent();
          port.DataReceived += 
               new SerialDataReceivedEventHandler(port_DataReceived);
            
      }

      private void Form1_Load(object sender, EventArgs e)
      {
          SetupControls();
      }

      private void SetupControls()
      {
          btnClosePort.Enabled = false;

          foreach (string str in SerialPort.GetPortNames())
              cbPortName.Items.Add(str);

          foreach (string str in Enum.GetNames(typeof(Parity)))
              cbParity.Items.Add(str);

          if (cbPortName.Items.Contains("COM1"))
              cbPortName.SelectedItem = "COM1";
          else cbPortName.SelectedIndex = 0;

          cbParity.SelectedIndex = 0;
          cbStopBits.SelectedIndex = 0;
          cbBaudRate.SelectedIndex = 3;
          cbDataBits.SelectedIndex = 3;
          cbLineTermination.SelectedIndex = 1;

      }

      private void btnClosePort_Click(object sender, EventArgs e)
      {
          port.Close();
          btnClosePort.Enabled = false;
          btnOpenPort.Text = "Open Port";
          rtbDisplay.SelectionColor = Color.Red;
          rtbDisplay.AppendText(port.PortName + " closed!\n");
          rtbDisplay.ScrollToCaret();
      }

      private void btnSend_Click(object sender, EventArgs e)
      {
          string lineTermination = string.Empty;

          if (!port.IsOpen)
          {
              rtbDisplay.SelectionColor = Color.Red;
              rtbDisplay.AppendText("Error: Not Connected to Port! 
                                     Establish connection first.\n");
              rtbDisplay.ScrollToCaret();
              return;
          }

          rtbDisplay.SelectionColor = Color.Green;
          switch (cbLineTermination.SelectedIndex)
          {
              case 0:
                 lineTermination = string.Empty;
                 break;
              case 1:
                 lineTermination = "\n";
                 break;
              case 2:
                 lineTermination = "\r";
                 break;
              case 3:
                 lineTermination = "\n\r";
                 break;
              default:
                 break;
          }
          rtbDisplay.AppendText("TX: " + txtSend.Text + "\n");
          port.Write(txtSend.Text + lineTermination);
          rtbDisplay.ScrollToCaret();
      }

      private void btnOpenPort_Click(object sender, EventArgs e)
      {
          if (port.IsOpen == true)
            {
              port.Close();
              rtbDisplay.SelectionColor = Color.Red;
              rtbDisplay.AppendText(port.PortName + " closed!\n");
              rtbDisplay.ScrollToCaret();
          }

          port.PortName = cbPortName.SelectedItem.ToString();
          port.BaudRate = int.Parse(cbBaudRate.SelectedItem.ToString());
           
          port.DataBits = int.Parse(cbDataBits.SelectedItem.ToString());
          
          port.StopBits = (StopBits)Enum.Parse(typeof(StopBits), 
                                      cbStopBits.SelectedItem.ToString());
          
          port.Parity = (Parity)Enum.Parse(typeof(Parity), 
                                      cbParity.SelectedItem.ToString());

          port.Open();
          if (port.IsOpen == true)
          {
              btnOpenPort.Text = "Refresh Port";
              btnClosePort.Enabled = true;
              rtbDisplay.SelectionColor = Color.Red;
              rtbDisplay.AppendText(port.PortName + " opened!\n");
              rtbDisplay.ScrollToCaret();
          }
      }

      void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
      {
          this.Invoke(new EventHandler(
              delegate
              {
                  rtbDisplay.SelectionColor = Color.Blue;
                  rtbDisplay.AppendText(port.ReadExisting());
                  rtbDisplay.ScrollToCaret();
              }));
      }

  }
}


More on the web:

Jan Axelson's Lakeview Research
#region Coad's Code (Noah Coad)
Your Electronics Open Source
RS-232 and Serial Communication