Wednesday, December 28, 2011

An implementation of a basic character LCD controller in Verilog

For a while now, I have been wanting to post my code that I developed during my GPS project using a FPGA board. Creating the LCD controller module was the meat of the project and I know many people are interested in how one might approach such a project. I have plans on providing a full-fledged tutorial on how I designed this module, but it is still in the works. In the meantime, I will provide you with the Verilog code which is fairly well commented and with a little cross correlation with the data sheet for the ST7066 the code should be for the most part, self-explanatory. Eventually this post will be edited with a more formal discussion of this code but for now we will have to make due with just the code.

Here is a screenshot of a simulation of what this module does after the initialization phase and you write the ascii value of "C" (0x43) as a data operation. The markers indicate the start and end of the module's execution of this operation.



DOWNLOAD: FPGA_2_LCD.v

Saturday, September 17, 2011

C/C++ Callback functions

So one of my projects I have been working on with the Arduino UNO required the use of an interrupt. For those not familiar with an interrupt it essentially is a mechanism that allows the code to branch off of its normal routine and execute a separate set of code. This is great for devices such as a rotary encoder that act as a volume knob or some other control mechanism since it will immediately interrupt the current code and execute the code associated with the interrupt. I was developing a nice set of library functions for a rotary encoder class library and thought that it would be nice to have a command like:

Rotary ROT;
ROT.begin(EncA,EncB,PB,CallbackFcn);

The purpose of this method would be to configure the rotary encoder inputs (EncA, EncB) to their proper modes and then create a callbackfcn that would execute every time one of these changed. The arduino library has a function that allows you to attach an interrupt to a pin and associate that interrupt pin with a callback function. But I wanted to allow the user to utilize my Rotary Class without having to specify the callback function within the library itself. This required me to learn how to create a "function pointer".

To create a function pointer is simple. Suppose we have a local function called CallbackFcn that takes in no input arguments. We can create a method that takes a function pointer as an input argument such as:

void Rotary::begin(int EncA, int EncB, int PB, void (*CALLBACK)(void)){
 //Stuff goes here
}

That is all there is to it.

Tuesday, August 2, 2011

Si4735 AM/FM/SW/LW Radio Project

[KEY DOWNLOADS] 




[UPDATE #9] 


Summary of changes specific to Si4735 library:
  • Added support for USE flags. These flags make it quick and easy to strip down the Si4735 library features and will ultimately help you save memory space at the cost of features.
  • Added setProperty and getProperty methods. This will make it very easy for individuals to easily customize the functionality and properties of the Si4735 chip. Consult the Si4735 programmers manual for the register addresses, properties, and acceptable values.
  • Added seekThresholds method to allow the user a quick and easy way to adjust the seek SNR and RSSI thresholds.
  • Added a new field to the Station struct that indicates when the radioText has changed (or is being changed). The radio text is usually left unchanged during a song so this could be used to detect that a new song is playing and you could create an event that triggers off of this flag. This boolean field should only stay high for one readRDS call.
Summary of changes to my project and helper libraries:
  • 'visible' method added to SerLCD.
  • Added a reset baud function to the setBaud method in SerLCD. Issuing setBaud(0) while the splash screen is being displayed will set SerLCD to 9600 baud.
  • Fixed typo in serCommand method in SerLCD library
  • increased stability of sketch by disabling interrupts during callback execution. This should help minimize the frequency of system freeze-up (I don't think it eliminates it completely though).
  • SerLCD is automatically reconfigured to it's maximum supported baud rate of 38400baud. Note there is a known bug where after a cold start-up (arduino completely discharged) that the sketch will not complete the setup process (it will stop at "Loading-Up"). A simple reset will allow it to successfully load.
  • Increased the seek process' sensitivity. It will now detect more "good" quality stations by default.
Si4735 Shield with custom made Logic Level Converter PCB attached


[UPDATE #8] I have updated the library once again. Here is an incomplete list of changes:

  • Updated the code to be compatible with the Arduino IDE v1.0 
  • Added SerLCD.cpp to the repo. SerLCD.h is now an actual class library.
  • Added Rotary_one class library to the repo. This is a single interrupt rotary encoder library. It is not prefect by any means but it is a step in the right direction. Freeing up pin 2 means I can start working on utilizing the Si4735 interrupt capabilities. The original rotary encoder library is left untouched and the two are interchangeable. By default the original is still being used, but in the future, I plan on fine tuning this library so that it is as responsive as the old one, but I have no plans on when that may be.
  • Made minor adjustments to my Si4735_Advanced_Radio project to address a few minor bugs. Audio quality will be slightly cleaner on stations that don't have RDS/RBDS program services. I was constantly writing on the UART line in these circumstances, which created unnecessary noise.



[UPDATE #7] My advanced radio project file is now included under the examples section of the Si4735 library repository. I also made a small update to the library to adjust the deemphasis to the proper levels depending on the region/locale you have specified when calling the setLocale method.



[UPDATE #6] I have finally made my radio project public! For now you can download my pde file and the accompanying libraries (with exception to the Si4735 library which you can just grab the normal way) in my GitHub downloads section. I am still trying to learn how to add files to an existing fork'ed repository, but once I figure that out, I will be adding these files to the "examples" folder in the Si4735 repo. If you have any questions pertaining to this project please let me know. I tried my best to comment most of the code without being overly verbose so some stuff is bound to cause a few people to scratch their heads.


Hopefully this example will provide users with enough insight on how "one" might use the different features that exist in the library.


I still have plans to add USE_FLAGS (as described in the previous update) but I have been busy with other things at the moment.



[UPDATE #5] The Si4735 library has been updated again, here are some of the changes:

  •  Added the retrieval of the UTC month, day, and year(2-digit). Note the hour and minute that are provided in the "Today" structure are local values and not the UTC values. This may change in the future.
  • Fixed the hour and minute computation. These were being incorrectly computed due to a couple mathematical errors.
  • Compacted the Program Type lookup tables into one large LUT. This reduces redundancy and ultimately saves space.
  • Added a private function that helps filter out non-printable characters from strings that are meant to be printed.
I have been playing with the idea of adding in USE_FLAGS to enable/disable the various RDS/RBDS features. I think this might be useful for individuals that want to minimize their memory footprint and compile only the portions of the code that are actually being used. Just a thought...

    [UPDATE #4] This is a quick update to show my audio amplifier circuit at work. I decided against throwing in a preamp into the mix and just went with an LM386N-1. The audio quality is very nice considering the parts being used. There is a little bit of audio clipping occurring when I set the audio at 100%, which I imagine I can eliminate by swapping out my 9V regulated DC adapter with a 12V regulated DC adapter. The speaker that I used was one of my car's old stock speakers. I plan to make another identical circuit so that I can get stereo output, but before I get into that, I will need to start thinking of an enclosure to start housing this stuff.




    Also, one thing I forgot to show off last time was my scanFreq Labview program that communicates with the Arduino and runs through a series of tuneFrequency() and getRSQ() calls. The program takes the SNR information acquired from the chip and plots it versus frequency. This is makes for a very basic spectrum analyzer over the FM frequency band. I would not rely on the metrics too much but they certainly give you a general idea of what to expect for sound quality when tuning to a particular frequency.



    For those interested in this you can download it here: download (note: make sure to change the REFRESH/HOLD button to REFRESH when you want to reacquire the data. HOLD will simply maintain the current data)
    The code essentially expects comma separated values (see the code below for the exact form of the output). The function below will interface with the Labview code perfectly (assuming you define your Si4735 class as "radio" and that you are using my latest version of the library). 



    [UPDATE #3] I got around to updating the Si4735 library. BE WARNED, this update WILL BREAK YOUR CODE...however, in my opinion this update is a necessary step forward and future updates will be less painful for both the users and the developers. Here is an incomplete list of changes and additions:
    • Created a Metrics structure, making the getRSQ method a lot simpler to interface
    • Created a Station structure, making the getRDS method a lot simpler to interface
    • Created a getTime method and a Today structure which acquires the station's local time (eventually this will also include the date, but currently it only contains the 24-hour time). Note this data field is rarely transmitted (most stations send time/date information about 1 time a minute)
    • Removed unused return values (mainly to clean up the code)
    • Added the ability to set (and get) the "locale" (setLocale) to either NA (North American) or EU (European). This effectively sets the look-up table to use for the Program Type.
    • Added setMode and getMode methods. The setMode method calls the "end" method which effectively powers down the Si4735 and the changes then mode. The user is responsible for calling the "begin" method again.
    • Added the interpretation/conversion of the PI field to a Callsign. It seems that not many stations (atleast where I live) use this field. The callsign is the 4 (or 3) letter identification assigned/used by radio station, such as WHEB or KHNN. Note: 3 letter stations are currently not supported in this code but it is on my list of TODOs.
    This was a rather large update and if something doesn't seem quite right please let me know, as I could have forgotten to change something when I went to update the repository.

    My next update will be a small one which is to enable the "date" field in the Today structure. This date field will contain the current year, month, and day.

    Also as a side note, I will be providing access to my Arduino Sketch in the near future.  This will probably be at the same time I perform the above mentioned update to the library


    [UPDATE #2] Here is another update showing performance improvements and added features such as showing the Program Type field (PTY). I have also added a getRSQ method to the library that can be used to get the "Received Signal Quality" of the tuned station. This method provides the following metrics:
    STBLEND - Percent Stereo Blend [0 = Mono, 100 = Stereo]
    RSSI - Receive Signal Strength Indicator [0 - 127 dBuV]
    SNR - Signal to Noise Ratio [0 - 127 dB]
    MULT - Multipath [0 = No multipath, 100 = Full multipath]
    FREQOFF - Signed Frequency offset
    For those interested in accessing the library that my code is running off of (for the most part...there are some minor differences), you can head over to: github Si4735. This is a fork of Trunet's repository with some additions, tweaks, and minor bug fixes.



    [UPDATE #1] Below is a video update to my project. I have now added RDS/RBDS support to my project as well as a LabView interface for controlling the device through the USB/COM port.



    ORIGINAL POST



    I recently acquired an Arduino board and I have found that it is at least 100 times easier to develop/design projects than an FPGA. Don't get me wrong I still prefer FPGA (I feel like I am more in control of what I do), but programming hardware from a C/C++ level is so much easier in comparison to HDL programming. This fact, coupled with the fact that the Arduino is an open source, driven community, hardware/software platfrom makes for a very user friendly environment. 

    Anyways, I decided to jump into the realm of Radio by using Sparkfun's  Si4735 Shield. The Si4735 is a pretty impressive chip that has a lot of functionality in a small form factor. Check out the video and see the basic block diagram of this project. When I get around to it, I will provide more details here.

    Things that need improving:
    1. You might have noticed in the video that the rotary encoder had an issue when I was attempting to change the frequency in "stepped" mode. This is a bug that currently only exists while in this mode. I am not sure if the underlying cause is my rotary encoder's debouncing algorithm or if it is some weird timing issue. This was fixed via modification to my rotary encoder callback procedure
    2. The rotary encoder's debouncing algorithm also needs improvement, while the performance is reasonable, it is far from perfect and needs some fine tuning. Updating my code and cleaning up my wiring helped a lot.
    3. There appears to be an issue with using a power source connected to the Arduino's external power jack (instead of using the USB's supplied power). The SPI interface becomes a little unreliable.
    Overall though this project, when powered from the USB port, is very reliable and user friendly. I have a few neat ideas for adding onto this project that I will share at a later time. The performance of the Radio shield is very good considering that the FM signal that I was receiving were coming from the line out (that is wired to my amplifier and speakers), and the audio quality was exceptional. 

    Sunday, June 26, 2011

    MTK NMEA checksum calculation

    The MTK NMEA checksum can be calculated by using the following procedure:

    The NMEA Checksum is calculated on a character by character basis using an XOR operator. Each character is fed into an XOR with the current checksum value. The checksum is initialized to all zeros. The characters that exist between the "$" and "*" are the only characters to be used in the calculation. These values are in ASCII, thus each character is represented as an 8-bit value. The resulting checksum is an 8-bit HEX value which is represented as 2 ASCII characters. Below is an example of this procedure:

    $PMTK000*32


    0000 0000 <==Checksum
    0101 0000 <==P

    0101 0000 <==Checksum
    0100 1101 <==M

    0001 1101 <==Checksum
    0101 0100 <==T

    0100 1001 <==Checksum
    0100 1011 <==K

    0000 0010 <==Checksum
    0011 0000 <==0

    0011 0010 <==Checksum
    0011 0000 <==0

    0000 0010 <==Checksum
    0011 0000 <==0

    0011 0010 <==Checksum

    This results in a checksum of 32 which matches what was shown above.

    And for those folks that use MATLAB, HERE is a very basic program that I wrote up that does this for you.

    Enjoy!

    Saturday, June 25, 2011

    GPS to 16x2 Character LCD Using an FPGA


    This is a project that uses a Spartan-3E FPGA Board (Xylo-LM) to grab the serial stream transmitted by a Locosys LS20031 GPS Module and parse the messages for the latitude and longitude. The latitude and longitude values are then feed into a 16x2 Character LCD display on a push of a button.

    Note: The GPS coordinates shown will not lead you to me. The GPS module at the time of recording this, was not locked onto my coordinates...so don't try hunting me down..else you will find yourself in the Atlantic =P

    Below is a basic block diagram that helps to illustrate what the FPGA does in the system. The FPGA has 3 modules: A Serial Module, a Parser Module, and an LCD Controller Module. The serial module is only responsible for acquiring the serial data at the specified baud rate. Over sampling is used in the FPGA to help minimize bit errors.  The serial module passes the raw data to the parser module. At this point in time the raw data is the NMEA messages (with the overhead information removed, i.e. stopbit/startbit). The parser module waits for the occurrence of a '$' which indicates the start of an MTK/NMEA message. Once the '$' is received, the parser extracts the message type and checks for a "GGA" message. If the current message is a GGA message, then we extract the Latitude and Longitude based on the standard format of the GGA message. This is currently being done by counting the characters; however, counting the comma delimiters work just as well. The parser module passes the latitude and longitude data to the LCD module as it is received on the serial line. The LCD controller module handles the initialization process required to set the LCD module into an operative mode, and it handles all the timing and writing data to the display.



    This is an on-going project and I plan to add many more features to it. Below are some changes that I plan on making in the future.

    Future Improvements/Additions:

    • Write the serial stream from the serial module to a Block Memory or RAM
    • Read the data in a Block Memory or RAM and feed the data into the Parser Module.
    • Perform mathematical operations on the acquired data, such as computing the displacement from the current location to the last saved location.

    For those interested in knowing more about this project, or want more information about certain aspects of the HDL code that I wrote, please don't hesitate to post a comment.

    For those interested in the LCD controller module's code, go here: LCD Controller.
    Or to download all of the related HDL files, go here: GPS2LCD_Files.zip

    My project was featured on Sparkfun's Main Page! Pretty cool and I got some good constructive criticism.

    Thursday, May 19, 2011

    Using an MCP3002 ADC for Interfacing an FPGA with a Photocell

    The MCP3002 ADC Chip is a very handy device. You can interface with it via a very simple SPI (Serial Peripheral Interface) protocol. The Verilog module that I designed to interface with this chip works beautifully.

    The module I created uses both channels of the MCP3002 in an "interlaced" single-ended mode. The module is strictly configured to work with a local oscillator of 24MHz, but minor adjustments to the process that converts the local clock to a 1.2MHz clock is all that needs to be modified. The 1.2MHz clock is the maximum frequency that the IC can operate at while powered at 2.7V as specified in the datasheet (pg3) under the "Timing Parameters". In my case my FPGA uses 3.3V logic so Fclk(max) should reside somewhere between this and 3.2MHz. If we assume a linear relationship between voltage and operating frequency, then the maximum expected operating frequency at 3.3V would be ~1.688MHz, thus operating at 1.2MHz "should" be a safe level of operation while pushing the IC to work at its maximum.

    As far as the code goes, it is really self explanatory. I would recommend anyone that is attempting to use this code to have a copy of the datasheet on hand so that you can see the relationship from my code and the datasheet's timing diagram. Figure 5-1 was specifically used to design this Verilog Module.

    On a hardware interfacing note, be sure to pay attention to Figure 4-2 in the datasheet, this clearly states that the ADC's CH0 and CH1 input signals NEED to be buffered (i.e. use an opamp in a buffer configuration or similar). If you skip this, your maximum operating frequency will be lower that the one defined in the datasheet.

    The code that I provide here is free to use however you would like, but I would appreciate it if you give me credit for my work. Also constructive criticism is welcome, if you see something that could be done better another way, let me know.

    Download: MCP3002 ADC Module

    Monday, May 2, 2011

    Setting up OpenCV in Eclipse on Windows (OpenCV2.2)

    The latest release of OpenCV (version 2.2) has undergone dramatic changes to the library. Because of these changes, my older guide is now outdated. For OpenCV version 2.2, please use this guide.

    First download and setup the basics:
    • Get MinGW
    • Download Eclipse C/C++ IDE
    Note: I have a tutorial on these two steps already so just head over HERE for more info.

    • Next download/install OpenCV 2.2
    • Now launch Eclipse and start a new project by going to:
    1. File->New->C++ Project (or File->New->C Project)
    2. Give your project a name in the "Project name" box
    3. Select the "Hello World" option under the "Project Type" section under the"Executable" folder. I recommend this over the "Empty Project" as it creates the c/c++ file for you instead of having to do it manually (it also creates a "src" folder and a"Debug" folder which helps keep things a little more organized)
    4. Make sure the "MinGW" Toolchain is selected in the "Toolchains" section
    5. Hit NEXT
    6. Fill in your Author and other file information, then hit NEXT
    7. In the next window select "Advanced settings...". This will bring you to the "Project Settings" which can always be accessed later by going to Project->Properties
    8. Under the "C/C++ Build" Section go to the "Settings" and select the "Tool Settings"Tab. Then select the "Includes" folder (on older versions of eclipse it is the "Directories" folder) in the GCC Compiler branch and add the opencv include directory to Include paths (-I): "C:\OpenCV2.2\include\". Of course, change C:\OpenCV2.2 to match the installed path that you used.
    9. Now, under the MinGW Linker select the "Libraries" folder and add the following to the Libraries (-l) section (note not all of these are necessarily needed for your project but these are all the libraries available in opencv version 2.2):
    • opencv_calib3d220
    • opencv_contrib220
    • opencv_core220
    • opencv_features2d220
    • opencv_ffmpeg220
    • opencv_flann220
    • opencv_gpu220
    • opencv_highgui220
    • opencv_imgproc220
    • opencv_legacy220
    • opencv_ml220
    • opencv_objdetect220
    • opencv_ts220
    • opencv_video220
    In most cases you will only need opencv_core220 and opencv_highgui220 to get started

    NOTE: Versions 2.2 and later postfix the libraries names with a three digit number that corresponds to the version of OpenCV that you are linking to.

    FINALLY, under the "Library search path (-L)" section add:
    • "C:\OpenCV2.2\lib"
    1. Hit OK when done
    2. Hit Finish to create and start the Project
    Write up a simple program to test if opencv works properly. You can use this EXAMPLE CODE I made to test if your video camera and environment are working properly.

    NOTE: The way this guide was written will require you to use a relative path to specify the header files you wish to include. OpenCV breaks up the library into two sections, "legacy libraries" and "new libraries".

    If you wish to specify one of the new opencv libraries use the following format:

    #include "opencv2\[subfolder]\[library.hpp]"

    ADDITIONALLY, if you wish to include all of the primary opencv2 header files in a project you can use:

    #include "opencv2\opencv.hpp"

    Note: opencv.hpp does not include every library in OpenCV2.2. It may be helpful for you to view the "opencv.hpp" library (located by default in: C:\OpenCV2.2\include\opencv2\opencv.hpp) to see what is included and how you can reference the new libraries in your code. To see the complete list of libraries available, go to "C:\OpenCV2.2\include\" and browse around the directory.

    Legacy libraries can be defined by: #include "opencv\[library.hpp]"


    If you get an error, during compile time, pertaining to:
    __exchange_and_add
    Then visit this page and follow the instructions under:
    Building on Windows using MinGW 3.4.5

    Hope this helps!

    Tuesday, February 15, 2011

    UWB Channel Model with People Shadowing Process


    This past semester was my final semester as a Graduate at UNH. It certainly feels good to have made it this far in my education and looking back on what I have acquired in knowledge both through the University and through my own interests has astounded me. This paper was my very last paper I wrote and it was on quite an interesting topic concerning a UWB channel model with the People Shadowing Process (PSE).

    Here is the abstract:
    This report covers the topic described by, A Packet-Level Model for UWB Channel with People Shadowing Process Based on Angular Spectrum Analysis, written by Ruonan Zhang and Lin Cai. The presented closed-form solutions to Angular Power Spectrum Analysis, the People Shadowing Process, and the Finite State Markov Chain Model will be discussed and related to the general material learned during a graduate-level Wireless Communications course. Simulation results will be compared and analyzed. This paper will confirm that the results present by Ruonan Zhang and Lin Cai are valid methods to simulate the people shadowing process for a packet-level model for UWB channels.

    Here is the link to the paper: PAPER

    Friday, January 7, 2011

    Dithering Methods and Applications


    This is a paper I wrote during my first year as a Grad Student. It covers the topic of Digital Halftones and Dithering. The paper was written with the intention of explaining the differences and general mechanisms for different dithering algorithms and to give the reader a solid understanding of why and when dithering is desirable. Below is the abstract followed by the link to the document.

    In this paper, the topic of digital halftones, or dithering, is discussed. In particular, the methods of implementation are discussed for the three classical categories which are random, ordered, and error diffusion dithering. A good understanding of dithering is necessary prior to understanding how and when dithering is necessary or beneficial to the designer. This paper includes discussions of specific types of dithering including one of the most popular techniques called Floyd-Steinberg and also includes actual implementations in MATLAB [See Appendix]. Several applications will be discussed that encompass not only image processing but audio signal processing, and optics.