Menu

Use_NetV_as_a_serial_interface_-_16_bits

This implementation of NETV, known as NETV16 (16 bits), is made to be used on any PIC24/dsPIC30F/dsPIC33F micro controller with a serial connection to a PC. This guide describes how to use the library with your own project. This is the kind of implementation that is useful if you want to plot variables on a PC, tune a controller, run your hardware with scripts, etc.

Images

[-img src=Netv ucontrol 1.png: missing =-]

[-img src=IMG 7163.JPG: missing =-]

Assumptions

  • PIC24/dsPIC30F/dsPIC33F
  • Hardware UART
  • USB to serial interface, Virtual COM Port (FT232, MCP2200, etc.)

Files

First of all, you need to get the library from our SVN repository. Here are the files that you need:

  • NETV16_Common.c / NETV16_Common.h : The protocol itself (identification, memory access, etc.)
  • NETV16_Shared.c / NETV16_Shared.h : Shared variables
  • NETV16_Memory.c / NETV16_Memory.h : Memory access
  • NETV16_SerialDriver.c / NETV16_SerialDriver.h : Serial (UART) driver.
  • NETV16_Utils.h: Macros and definitions

Some files are application-specific for your project:

  • NETV16_Shared_project-name.c / NETV16_Shared_project-name.h : Module definition and shared variables
  • NETV16_bsp.h : Definitions and includes
  • usart.c/usart.h: For a serial implementation you need those files. More details in the next section.

How to use the library in a PIC project

Main file

Note: this example is based on the dsPIC33F Test Project (available on the SVN).

In your main project file (let's call it main.c) you need to add includes:

#include "NETV16_SerialDriver.h"
#include "NETV16_Device.h"
#include "NETV16_Shared.h"
#include "NETV16_Memory.h"

In void main (void) you need to add two lines at the top:

unsigned char canAddr = 0;
BootConfig *bootConfig = NULL;

and the boot config just before your while loop:

    //reading boot config and device configuration
    //MUST BE DONE BEFORE INITIALIZING NETV MODULE
    bootConfig = netv_get_boot_config();
    //dsPIC33F w/o eeprom:
    bootConfig->table_version = MODULE_TABLE_VERSION;
    bootConfig->project_id = MODULE_PROJECT_ID;
    bootConfig->code_version = MODULE_CODE_VERSION;
    //Set to default address
    bootConfig->module_id = 1;

    if (bootConfig)
    {
            //read configuration
            netv_read_boot_config(bootConfig);

            //safety
            bootConfig->module_state = BOOT_NORMAL;

            //verify if we have correct configuration
            //write it back if not updated
            if (bootConfig->table_version !=  MODULE_TABLE_VERSION
            || bootConfig->project_id != MODULE_PROJECT_ID
            || bootConfig->code_version != MODULE_CODE_VERSION)
            {
                    bootConfig->table_version = MODULE_TABLE_VERSION;
                    bootConfig->project_id = MODULE_PROJECT_ID;
                    bootConfig->code_version = MODULE_CODE_VERSION;

                    //Set to default address
                    bootConfig->module_id = 1;

                    //Writing back the boot config for the next version
         //           netv_write_boot_config(bootConfig);                   //Not used now (no eeprom)

                    //set variables to zero
                    init_default_variables();
            }
    }

    //UPDATE NETV ADDRESS
    canAddr = bootConfig->module_id;

In your main loop, you need to add the transceiver function. In that case, I also refresh my variables in the main loop.

    //Main loop
    while(1)
    {
         //Right now will never come out of this function (blocking on serial port)
         netv_transceiver(canAddr);
     update_variables();
    }

In the same main.c file, you need to add several functions:

void netv_proc_message(NETV_MESSAGE *message)
{
    //Handle custom messages...
}

void init_default_variables(void)
{
    memset(&g_globalNETVVariables, 0, sizeof(GlobalNETVVariables));
}

For the test project, here is what it looks like:

void netv_proc_message(NETV_MESSAGE *message)
{
    //Handle custom messages...
}

void init_default_variables(void)
{
    memset(&g_globalNETVVariables, 0, sizeof(GlobalNETVVariables));
}

void update_variables(void)
{
    g_globalNETVVariables.Count++;  //Sawtooth waveform

}

Finally, you need to deal with incoming data in your ISR. In the test project those functions are in interrupt.c.

//Uart1 Receive
void __attribute__ ((interrupt, no_auto_psv)) _U1RXInterrupt(void)
{
    //Handle USART Interrupt
    serial_usart_interrupt_handler();

    IFS0bits.U1RXIF = 0;    //Clear flag
}

//Uart1 Emit
void __attribute__ ((interrupt, no_auto_psv)) _U1TXInterrupt(void)
{
    //Should not happen...
    IFS0bits.U1TXIF = 0;    //Clear flag
}

usart.c/usart.h

Since there is no clear convention of registers and bits name for different PIC controllers, we need to customize the usart.c file for a specific project. The function names are fixed and should not be changed (the SerialDriver wouldn't know where to look).

Here is a typical usart.h file with function prototypes:

#ifndef INC_UART_H
#define INC_UART_H

//Important: to use NetworkViewer, keep these function names!

/////////////////////////////////////////////////////////////////////////////
//                                                                         //
//                          Function prototypes                        //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

void setup_usart1(void);
void putc_usart1(char data);
char getc_usart1(void);
char busy_usart1(void);
char datardy_usart1(void);
void puts_usart1(char *data);
void gets_usart1(char *buffer, unsigned char len);

#endif

In the usart.c file, you need to "fill" each function according to the datasheet. You can look in the Microchip's library for inspiration. Here is the file for the test project:

#include "usart.h"
#include "def.h"


//////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                          //
//                                    Constants and variables                               //
//                                                                                          //
//////////////////////////////////////////////////////////////////////////////////////////////

char uart_buf[128]; //Caracter buffer

//////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                          //
//                                           Functions                                      //
//                                                                                          //
//////////////////////////////////////////////////////////////////////////////////////////////

void setup_usart1(void) 
{
    //UART1 config: Fcy = 36.85MHz, 57600 8N1

    // configure U1MODE
    U1MODEbits.UARTEN = 0;  // TX, RX DISABLED, ENABLE at end of func
    U1MODEbits.USIDL = 0;   // Continue in Idle
    U1MODEbits.IREN = 0;    // No IR translation
    U1MODEbits.RTSMD = 0;   // Simplex Mode
    U1MODEbits.UEN = 0;     // TX,RX enabled, CTS,RTS not
    U1MODEbits.WAKE = 0;    // No Wake up (since we don't sleep here)
    U1MODEbits.LPBACK = 0;  // No Loop Back
    U1MODEbits.ABAUD = 0;   // No Autobaud
    U1MODEbits.URXINV = 0;  // IdleState = 1
    U1MODEbits.BRGH = 0;    // 16 clocks per bit period
    U1MODEbits.PDSEL = 0;   // 8bit, No Parity
    U1MODEbits.STSEL = 0;   // One Stop Bit

    //  U1BRG = (Fcy/(16*BaudRate))-1       (36.85MHz / (16 * 57600) - 1) = 39
    U1BRG = 39;

    U1STAbits.UTXISEL1 = 0; //Int when Char is transferred (1/2 config!)
    U1STAbits.UTXINV = 0;   //N/A, IRDA config
    U1STAbits.UTXISEL0 = 0; //Other half of Bit15
    U1STAbits.UTXBRK = 0;   //Disabled
    U1STAbits.UTXEN = 0;    //TX pins controlled by periph
    U1STAbits.UTXBF = 0;    //*Read Only Bit*
    U1STAbits.TRMT = 0;     //*Read Only bit*
    U1STAbits.URXISEL = 0;  //Int. on character recieved
    U1STAbits.ADDEN = 0;    //Address Detect Disabled
    U1STAbits.RIDLE = 0;    //*Read Only Bit*
    U1STAbits.PERR = 0;     //*Read Only Bit*
    U1STAbits.FERR = 0;     //*Read Only Bit*
    U1STAbits.OERR = 0;     //*Read Only Bit*
    U1STAbits.URXDA = 0;    //*Read Only Bit*

    IPC2bits.U1RXIP = 0b100;    // Mid Range Interrupt Priority level
    IPC3bits.U1TXIP = 0b100;    // Mid Range Interrupt Priority level

    IFS0bits.U1TXIF = 0;    // Clear the Transmit Interrupt Flag
    IEC0bits.U1TXIE = 1;    // Enable Transmit Interrupts
    IFS0bits.U1RXIF = 0;    // Clear the Recieve Interrupt Flag
    IEC0bits.U1RXIE = 1;    // Enable Recieve Interrupts

    U1MODEbits.UARTEN = 1;  // And turn the peripheral on
    U1STAbits.UTXEN = 1;
}

void putc_usart1(char data)
{   
    U1TXREG = data & 0xFF;  //Write the data byte to the USART1 
}

char getc_usart1(void)
{   
    return (char)(U1RXREG & 0xFF);  // Return the received data 
}

char busy_usart1(void)
{
  if(!U1STAbits.TRMT)   // Is the transmit shift register empty
        return 1;       // No, return FALSE
  return 0;             // Return TRUE
}

char datardy_usart1(void)
{
    return(U1STAbits.URXDA);
}

void gets_usart1(char *buffer, unsigned char len)
{
    char i;                         // Length counter
    unsigned char data;

    for(i=0;i

NETV16_Shared_project-name.c/NETV16_Shared_project-name.c

The NETV16_Shared_project-name.h file contains the data structure GlobalNETVVariables that Network Viewer can read and write. Here is an example:

#ifndef _NETV16_SHARED_TEST_H_
#define _NETV16_SHARED_TEST_H_

#include "NETV16_Utils.h"

#define MODULE_TABLE_VERSION 0x02
#define MODULE_PROJECT_ID 0x01
#define MODULE_CODE_VERSION 0x01

typedef struct 
{
        uint16  FlashRate;
        uint8   Count;
        uint8   Free;
        uint16  Analog0;
        uint16  Analog1;
        uint16  Analog2;
        uint16  Analog3;
        uint16  Analog4;
        uint16  Analog5;
        uint16  Analog6;
        uint16  Analog7;
        uint16  Analog8;
        uint16  Analog9;
        uint16  Analog10;
        uint16  Analog11;
        uint16  Temp;
        sint16  Amp;
        uint16  Volt1;
        uint16  Volt2;

} GlobalNETVVariables;

#endif

The NETV16_Shared_project-name.c is minimalist and only contains one include:

#include "NETV16_Shared_test.h"

bsp.h

For the moment the bsp.h file is simple and only contains some definitions:

#ifndef _BSP_TEST_H_
#define _BSP_TEST_H_

#include <p33fj32mc304.h>

#define FCY 36850000
#include "NETV16_Shared_test.h"

//#define USE_EEPROM    //Comment for dsPIC33F

#define DEVID_BASE_ADDRESS 0x3FFFFE

//DEVICE MEMORY MAP INFORMATION 
#define EEPROM_BASE_ADDRESS 0x7FFE00
#define EEPROM_BASE_ADDRESS_LOW 0xFFFF
#define EEPROM_BASE_ADDRESS_HIGH 0x007F

#endif

How to use your PIC project with Network Viewer

Now that the PIC is programmed with the library, there is one last step to use it with Network Viewer: the XML config file. All the necessery information to write an application-specific file is on the [NetworkViewer] page. Here is an example:

<ModuleConfiguration moduleState="-1" deviceID="-1" projectID="1" codeVersion="-1" processorID="-1" tableVersion="-1" >
     <ModuleVariable offset="0"  description="Alive LED flash rate" type="uint16"  value="" name="FlashRate" />
     <ModuleVariable offset="2"  description="Counter" type="uint8" value="" name="Count" />
     <ModuleVariable offset="3"  description="Unused" type="uint8" value="" name="Free" />
     <ModuleVariable offset="4"  description="Analog input 0" type="uint16" value="" name="Analog0" />
     <ModuleVariable offset="6"  description="Analog input 1" type="uint16" value="" name="Analog1" />
     <ModuleVariable offset="8"  description="Analog input 2" type="uint16" value="" name="Analog2" />
     <ModuleVariable offset="10"  description="Analog input 3" type="uint16" value="" name="Analog3" />
     <ModuleVariable offset="12"  description="Analog input 4" type="uint16" value="" name="Analog4" />
     <ModuleVariable offset="14"  description="Analog input 5" type="uint16" value="" name="Analog5" />
     <ModuleVariable offset="16"  description="Analog input 6" type="uint16" value="" name="Analog6" />
     <ModuleVariable offset="18"  description="Analog input 7" type="uint16" value="" name="Analog7" />
     <ModuleVariable offset="20"  description="Analog input 8" type="uint16" value="" name="Analog8" />
     <ModuleVariable offset="22"  description="Analog input 9" type="uint16" value="" name="Analog9" />
     <ModuleVariable offset="24"  description="Analog input 10" type="uint16" value="" name="Analog10" />
     <ModuleVariable offset="26"  description="Analog input 11" type="uint16" value="" name="Analog11" />
     <ModuleVariable offset="28"  description="Temperature" type="uint16" value="" name="Temp" />
     <ModuleVariable offset="30"  description="Current" type="sint16" value="" name="Amp" />
     <ModuleVariable offset="32"  description="Voltage channel 1" type="uint16" value="" name="Volt1" />
     <ModuleVariable offset="34"  description="Voltage channel 2" type="uint16" value="" name="Volt2" />
</ModuleConfiguration>


Related

OpenECoSys-Wiki: HOWTO
OpenECoSys-Wiki: NETVProtocolStack::SerialImplementation
OpenECoSys-Wiki: NetworkViewer

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.