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.
[-img src=Netv ucontrol 1.png: missing =-]
[-img src=IMG 7163.JPG: missing =-]
First of all, you need to get the library from our SVN repository. Here are the files that you need:
Some files are application-specific for your project:
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
}
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
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"
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
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>
OpenECoSys-Wiki: HOWTO
OpenECoSys-Wiki: NETVProtocolStack::SerialImplementation
OpenECoSys-Wiki: NetworkViewer