Second Try & Abort

April 10, 2012 Leave a comment

I took a second shot at planing the table on my DIY CNC machine, but had to abort after several passes. All the new systems were working well, new router, dust extractor and vacuum system, but a rouge nut and washer appeared on the far side of the table. Once the machine was stopped with the E-stop button I found the nuts holding the bottom Z-axis drive shaft bearing mount were vibrating off.

Nut coming loose from under side of Z-axis carriage. Whoops-a-doodle.

I added some lock washers to all six bolts on the bottom side of the Z-axis carriage to prevent that from happening again. I suppose I should start checking things like nuts coming loose before firing up to cut, so lesson learned. It was lucky the nut and washer fell off out of the way of the router and that I noticed it.

Ready for the third attempt to mill the table flat.

Actually, I needed to restart from the beginning of the program with an offset down to correct a step between the first and second attempts. This also let me check if the new cyclone dust extractor worked on the fine saw dust produced from cutting the MDF board. The shroud made from a CD spindle cover worked rather well for its first real test. I’ll think about adding some brushes around the perimeter later, but was satisfied at how well it controlled the dust cloud that I’ll continue without for now.

Categories: CNC Machine Tags:

Cyclone Dust Extractor

April 10, 2012 8 comments

Before I start cutting again, I need a dust extractor to go along with the vacuum. The filter on the shop-vac was clogged with the dust I created from the first run so much it lost suction. Instead of spending $10 every few minutes on filters, I made a cyclonic dust extractor for the same amount. Since anyone with a CNC machine that cuts has one, there are plenty of plans online. I looked at a couple using a 5 gal. bucket and some PVC fittings that looked easy and went with that.

The $10 cyclone dust extractor.

The input to the extractor comes from the CNC machine and to a 90 degree elbow pointed toward the inside wall of the bucket. Then the output to the shop-vac is a single straight piece of PVC pipe, with the end inside the bucket higher than the elbow. Nothing complicated and parts were easily found at the big box store; 2″ PVC pipe section, elbow and two couplings and a general purpose bucket with lid. The hard part was trying to match  the two different hose diameters.

Dust filled air enters through the elbow, then falls due to gravity and letting the cleaner air continue to the shop-vac out the short pipe.

After gaining a third section of hose, sacrificed from a junk vacuum in the basement, I was able to make a permanent connection to the shroud and bungee cords. The shop-vac hose hooked to this new hose like it was meant to be, but was a trick to find a compatible PVC piece for the opposite end. I used my dremel tool and ground a step into the inner diameter of a section of 2″ PVC pipe to allow the shop-vac hose to fit into. I’ll still be able to disconnect this section to use the shop-vac for cleaning elsewhere. The last section of hose was an extension kit I bought for a different brand of shop-vacs and was naturally incompatible.  One end fits into the vacuum’s input well enough, but the opposite end to the extractor wasn’t near anything. I wound up cutting a slot on one end of a section of 2″ pipe and squeezed the end together with a pipe clamp till the hose fit over. Once the hose was on, the pipe clamp was released and any remaining holes taped over.

The PVC pieces for the output. The two pieces on the bottom are from one coupling cut in half. The smaller half on the right is then cut through perpendicularly to the end.

With the all the fittings made, they need to be connected through the bucket lid. The two holes were cut with a craft knife and care needs to be taken not to rip the material, because it’s easy to do. I scrapped a lid trying to epoxy the two PVC pipes in place, with both times breaking off immediately when moved side to side. Next I sandwiched the lid between two edges of pipe coupling that worked well. For the output section I cut a coupling in half, then cut through perpendicularly on only one of those halves (just one cut so it stays a ring, but opens wider). The solid coupling half goes on the straight pipe section, inside the bucket. On top of the lid, the cut coupling half can expand around the pipe to go all the way down easily. The PVC cement seems to melt the lid material to the pipe and fuses everything securely (and gives off some bonus fumes). The input side also needs a coupling cut in half, but only the piece with the extra cut like before; the edge of the elbow serves as the bottom part of the sandwich.

Only half of a coupling is needed for the input side, cut to go over the pipe easily.

Once the glue dried and the hoses were connected, I fired up the vacuum to test for leaks. Where hoses met, I sealed with duct tape. Then sealed leaks in the PVC/lid area with some silicone. While the vacuum was on, the wet silicone sucked into holes. I also revised the bungee cord rigging to hold the hose off of the work surface. With the gantry at is furthest position, the bungee cord was wrapped around the hose a few times and held in places with zip ties. When the gantry moved back to home, the hose naturally coils against the wall and out of the way. From the pic below, it looks like the cord is pulling hard on the hook in the wall, but there is still some slack left.

It worked! Some of the dust made it past to the shop vac, but not as much as this.

Eventually, I’ll move both the dust extractor and vacuum in the basement, with the switch controlled by the CNC software. But that will have to wait till I actually make something.

Categories: CNC Machine Tags:

Microchip Graphics Library Integration

March 23, 2012 10 comments

Here is some code for the eBay HX8347-A LCD I’ve been dinking with that utilizes the Graphics Library provided by Microchip. They have a few nice app notes on creating the graphical widgets on one of their development boards, but not really for a custom setup like my Commander32. All of their microcontrollers use the PMP feature to communicate with the LCD, while I just use pins directly.  Their help file gives a nice summary of copying the library files to a new project to keep the file structure intact. Once that is done, the following steps should help make your own setup.

Title Screen for GUI demo

Main Menu with images.

Button pressed on Main Menu.

  1. Write a new HardwareProfile.h

Write from scratch to contain the definition of the LCD pins to the microcontroller pins  and the clock frequency define for SYS_FREQ (required for library). This goes in source folder with your main.c file.

#define SYS_FREQ        (80000000)

// Definitions for reset pin
#define RST_TRIS_BIT    TRISGbits.TRISG12
#define RST_LAT_BIT     LATGbits.LATG12
#define    LCD_REST        RST_LAT_BIT

// Definitions for CS pin
#define CS_TRIS_BIT     TRISGbits.TRISG13
#define CS_LAT_BIT      LATGbits.LATG13
#define    LCD_CS            CS_LAT_BIT

// Definitions for RS pin
#define RS_TRIS_BIT        TRISGbits.TRISG15
#define RS_LAT_BIT      LATGbits.LATG15
#define    LCD_RS            RS_LAT_BIT

// Definitions for WR pin
#define WR_TRIS_BIT        TRISGbits.TRISG14
#define WR_LAT_BIT        LATGbits.LATG14
#define    LCD_WR            WR_LAT_BIT

// Definitions for WR pin
#define RD_TRIS_BIT        TRISDbits.TRISD9
#define RD_LAT_BIT        LATDbits.LATD9

// Data Port for 16 bits
#define    LCD_DATA        LATB
#define    LCD_DATA_TRIS    TRISB
#define DataPortIn()  LCD_DATA_TRIS = 0xffff;
#define DataPortOut() LCD_DATA_TRIS = 0x0000;
  1. Custom LCD Driver (HX8347A_16BIT.c &.h)

The Library contains some blank custom driver files (.c and .h in separate folders w/in library) with the two basic functions, DeviceReset() and PutPixel() required, but empty. My previous LCD initialization code was dumped into DeviceReset() and similarly with the PutPixel(). I also needed to write my own routines for ClearDevice() and Bar(), to optimize drawing. This required the appropriate lines in the header file to be uncommented to use these functions over the Library’s.

HX8347A_16BIT.c

/*****************************************************************************
 *  Module for Microchip Graphics Library
    HX8347 LCD Controller
 *  Custom display controller driver template
 *  By: Ryan Milewski, 2012
 *****************************************************************************/
#include "Graphics/Graphics.h"
#include "HardwareProfile.h"

// Color
WORD_VAL    _color;

// Clipping region control
SHORT       _clipRgn;

// Clipping region borders
SHORT       _clipLeft;
SHORT       _clipTop;
SHORT       _clipRight;
SHORT       _clipBottom;

/*********************************************************************
* Function:  void  DelayMs(WORD time)
* PreCondition: none
* Input: time - delay in ms
* Output: none
* Side Effects: none
* Overview: delays execution on time specified in ms
* Note: none
********************************************************************/
void DelayMs(unsigned int msec)
{
    unsigned int tWait, tStart;

    tWait=(SYS_FREQ/2000)*msec;
    tStart=ReadCoreTimer();
    while((ReadCoreTimer()-tStart)<tWait);        // wait for the time to pass

}

void LCD_write_COM(WORD data)
{

    LCD_RS = 0;
    LCD_CS = 0;
    LCD_DATA = data;
    LCD_WR = 0;
    //Nop();
    //Nop();
    //Nop();
    LCD_WR = 1;
    LCD_CS = 1;    

}

void LCD_write_DATA(WORD data)
{
    LCD_RS = 1;
    LCD_CS = 0;

    LCD_DATA = data;
    LCD_WR = 0;
    //Nop();
    //Nop();
    //Nop();
    LCD_WR = 1;
    LCD_CS = 1;

}//end of WriteLCD_DATA()

void LCD_write_COM_DATA(BYTE index, WORD value)
{
    LCD_write_COM(index);
    LCD_write_DATA(value);

}

/*********************************************************************
* Function:  void ResetDevice()
* PreCondition: none
* Input: none
* Output: none
* Side Effects: none
* Overview: resets LCD, initializes PMP
* Note: none
********************************************************************/
void ResetDevice(void)
{

    // Set uController pins TRIS
    AD1PCFG = 0xffff;    //analog pins all digital

    CS_TRIS_BIT = 0;
    RS_TRIS_BIT = 0;
    WR_TRIS_BIT = 0;
    RD_TRIS_BIT = 0;
    DataPortOut();

    //Reset LCD    
    LCD_REST = 1;
    DelayMs(5);    //5ms delay
    LCD_REST = 0;
    DelayMs(10);    //10ms delay
    LCD_REST = 1;
    DelayMs(20);    //20ms delay

    //Vendor gamma
    LCD_write_COM_DATA(0x0046,0x00a4);
    LCD_write_COM_DATA(0x0047,0x0053);
    LCD_write_COM_DATA(0x0048,0x0000);
    LCD_write_COM_DATA(0x0049,0x0044);
    LCD_write_COM_DATA(0x004a,0x0004);
    LCD_write_COM_DATA(0x004b,0x0067);
    LCD_write_COM_DATA(0x004c,0x0033);
    LCD_write_COM_DATA(0x004d,0x0077);
    LCD_write_COM_DATA(0x004e,0x0012);
    LCD_write_COM_DATA(0x004f,0x004c);
    LCD_write_COM_DATA(0x0050,0x0046);
    LCD_write_COM_DATA(0x0051,0x0044);

    //240x320 window settings
    LCD_write_COM_DATA(0x0002,0x0000);    //Column address start2
    LCD_write_COM_DATA(0x0003,0x0000);    //column address start1
    LCD_write_COM_DATA(0x0004,0x0000);    //Column address end2
    LCD_write_COM_DATA(0x0005,0x00ef);    //Column address end1
    LCD_write_COM_DATA(0x0006,0x0000);    //Row address start2
    LCD_write_COM_DATA(0x0007,0x0000);    //Row address start1
    LCD_write_COM_DATA(0x0008,0x0001);    //Row address end2
    LCD_write_COM_DATA(0x0009,0x003f);    //Row address end1

    //display settings
    LCD_write_COM_DATA(0x0001,0x0006);    //IDMON=0,INVON=1,NORON=1,PTLON=0
    LCD_write_COM_DATA(0x0016,0x0078);    //MY=0,MX=0,MV=0,ML=1,BGR=0,TEON=0
    LCD_write_COM_DATA(0x0023,0x0095);    //N_DC=1001 0101
    LCD_write_COM_DATA(0x0024,0x0095);    //PI_DC=1001 0101
    LCD_write_COM_DATA(0x0025,0x00ff);    //I_DC=1111 1111

    LCD_write_COM_DATA(0x0027,0x0002);    //N_BP=0000 0010
    LCD_write_COM_DATA(0x0028,0x0002);    //N_FP=0000 0010
    LCD_write_COM_DATA(0x0029,0x0002);    //PI_BP=0000 0010
    LCD_write_COM_DATA(0x002a,0x0002);    //PI_FP=0000 0010
    LCD_write_COM_DATA(0x002c,0x0002);    //I_BP=0000 0010
    LCD_write_COM_DATA(0x002d,0x0002);    //I_FP=0000 0010

    LCD_write_COM_DATA(0x003a,0x0001);    //N_RTN=0000,N_NW=001
    LCD_write_COM_DATA(0x003b,0x0000);    //P_RTN=0000,P_NW=001
    LCD_write_COM_DATA(0x003c,0x00f0);    //I_RTN=1111,I_NW=000
    LCD_write_COM_DATA(0x003d,0x0000);    //DIV=00
    DelayMs(1);    //1ms delay
    LCD_write_COM_DATA(0x0035,0x0038);    //EOS=38h
    LCD_write_COM_DATA(0x0036,0x0078);    //EQP=78h
    LCD_write_COM_DATA(0x003e,0x0038);    //SON=38h
    LCD_write_COM_DATA(0x0040,0x000f);    //GDON=0fh
    LCD_write_COM_DATA(0x0041,0x00f0);    //GDOFF

    //Power Supply Settings
    LCD_write_COM_DATA(0x0019,0x0049);    //CADJ=0100,CUADJ=100,OSD_EN=1,60Hz
    LCD_write_COM_DATA(0x0093,0x000f);    //RADJ=1111, 100%
    DelayMs(1);    //1ms delay
    LCD_write_COM_DATA(0x0020,0x0040);    //BT=0100
    LCD_write_COM_DATA(0x001d,0x0007);    //VC1=111
    LCD_write_COM_DATA(0x001e,0x0000);    //VC3=000
    LCD_write_COM_DATA(0x001f,0x0004);    //VRH=0011

    //VCOM Settings
    LCD_write_COM_DATA(0x0044,0x004d);    //VCM=101 0000
    LCD_write_COM_DATA(0x0045,0x000e);    //VDV=1 0001
    DelayMs(1);    //1ms delay
    LCD_write_COM_DATA(0x001c,0x0004);    //AP=100
    DelayMs(2);    //2ms delay
    LCD_write_COM_DATA(0x001b,0x0018);    //GASENB=0,PON=1,DK=1,XDK=0,VLCD TRI=0,STB=0
    DelayMs(1);    //1ms delay
    LCD_write_COM_DATA(0x001b,0x0010);    //GASENB=0,PON=1,DK=0,XDK=0,VLCD TRI=0,STB=0
    DelayMs(1);    //1ms delay
    LCD_write_COM_DATA(0x0043,0x0080);    //set VCOMG=1
    DelayMs(2);    //2ms delay

    //Display On Setting
    LCD_write_COM_DATA(0x0090,0x007f);    //SAP=0111 1111
    LCD_write_COM_DATA(0x0026,0x0004);    //GON=0,DTE=0,D=01
    DelayMs(1);    //1ms delay
    LCD_write_COM_DATA(0x0026,0x0024);    //GON=1,DTE=0,D=01
    LCD_write_COM_DATA(0x0026,0x002c);    //GON=1,DTE=0,D=11
    DelayMs(1);    //1ms delay
    LCD_write_COM_DATA(0x0026,0x003c);    //GON=1,DTE=1,D=11

    //Internal Register Settings
    LCD_write_COM_DATA(0x0057,0x0002);    //TEST_Mode=1: into test mode
    LCD_write_COM_DATA(0x0095,0x0001);    //SET DISPLAY CLOCK AND PUMPKING CLOCK TO SYCRONIZE
    LCD_write_COM_DATA(0x0057,0x0000);    //TEST Mode=0:exit TEST Mode

    LCD_write_COM(0x0022);
}

void LCD_address_set(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2)
{
    LCD_write_COM_DATA(0x0002,x1>>8);        //Column address start2
    LCD_write_COM_DATA(0x0003,x1);    //Column address start1
    LCD_write_COM_DATA(0x0004,x2>>8);        //column address end2
    LCD_write_COM_DATA(0x0005,x2);    //column address end1

    LCD_write_COM_DATA(0x0006,y1>>8);        //Row address start2
    LCD_write_COM_DATA(0x0007,y1);    //row address start1
    LCD_write_COM_DATA(0x0008,y2>>8);        //row address end2
    LCD_write_COM_DATA(0x0009,y2);    //row address end1

    LCD_write_COM(0x0022);
}

/*********************************************************************
* Function: void PutPixel(SHORT x, SHORT y)
* PreCondition: none
* Input: x,y - pixel coordinates
* Output: none
* Side Effects: none
* Overview: puts pixel
* Note: none
********************************************************************/
void PutPixel(SHORT x, SHORT y)
{
    unsigned int ncolor;
    ncolor = GetColor();
    LCD_address_set(x,y,x,y);
    LCD_write_DATA(ncolor);
}

/*********************************************************************
* Function: WORD GetPixel(SHORT x, SHORT y)
* PreCondition: none
* Input: x,y - pixel coordinates
* Output: pixel color
* Side Effects: none
* Overview: returns pixel color at x,y position
* Note: none
********************************************************************/
WORD GetPixel(SHORT x, SHORT y)
{
    return (0);
}

/*********************************************************************
* Function: void ClearDevice(void)
* PreCondition: none
* Input: none
* Output: none
* Side Effects: none
* Overview: clears screen with current color and sets cursor to 0,0
* Note: none
********************************************************************/
void ClearDevice(void)
{
    int i,j;
    unsigned int ncolor;

    ncolor = GetColor();
    LCD_address_set(0,0,DISP_HOR_RESOLUTION-1,DISP_VER_RESOLUTION-1);

    for(i=0;i<DISP_HOR_RESOLUTION;i++)
    {
        for(j=0;j<DISP_VER_RESOLUTION;j++)
        {
        LCD_write_DATA(ncolor);
        }
    }
}

/*********************************************************************
* Function: WORD Bar(SHORT left, SHORT top, SHORT right, SHORT bottom)
* PreCondition: none
* Input: left,top - top left corner coordinates,
*        right,bottom - bottom right corner coordinates
* Output: For NON-Blocking configuration:
*         - Returns 0 when device is busy and the shape is not yet completely drawn.
*         - Returns 1 when the shape is completely drawn.
*         For Blocking configuration:
*         - Always return 1.
* Side Effects: none
* Overview: draws rectangle filled with current color
* Note: none
********************************************************************/
WORD Bar(SHORT left, SHORT top, SHORT right, SHORT bottom)
{
    unsigned ncolor;
    int i,j;

    ncolor = GetColor();

    LCD_address_set(left,top,right,bottom);
    for(i=0;i<=(right-left);i++)
    {
        for(j=0;j<=(bottom-top);j++)
        {
            LCD_write_DATA(ncolor);
        }

    }
    return (1);
}
  1. Select options in GraphicsConfig.h

This should be copied from Microchip and placed in your project folder (like the help file says). Put in the Horizontal and Verticle resolution defines your LCD and uncomment the Graphics options to be used.

  1. Replace DeviceDriver.h with Custom Driver

There are two Library files that need to be changed to use the custom driver in the #includes; Primitive.c and Graphics.h. In my case, #include “DeviceDriver.h” was replaced with “HX8347A_16BIT.h”.

Primitive.c 

#include "HardwareProfile.h"              // needed to provide values for GetMaxX() and GetMaxY() macros
#include "HX8347A_16BIT.h"        //Change to custom driver header HERE!!
#include "Graphics/Primitive.h"
#include "Compiler.h" 

 

Then,

Graphics.h

////////////////////////////// INCLUDES //////////////////////////////
    #include <stdlib.h>             // needed because of malloc()
    #include "GenericTypeDefs.h"
	#include "GraphicsConfig.h"
    #include "HX8347A_16BIT.h"      // Display Driver layer
    #include "Primitive.h"          // Graphic Primitives layer
    #include "GOL.h"                // Graphics Object layer

At this point, the Library’s Primitive Layer can be tested. I just grabbed some example code to draw the basic shapes available, text, and some images. Yay!

  1. Custom Touchscreen Driver

The files Touchscreen.c and.h were copied to my project folder and renamed ADS7843Touchscreen.c and .h for customizing. Microchip’s dev boards all drive the touch screen using the ADC, but mine uses the ADS7843 chip which takes care of all that. I kept the function TouchGetMsg() which processes the touch actions into predefined states, and added my own code for initializing and TouchGetXY(). My function gets both x and y coordinates at the same time and needed multiple readings of each and averaged to reduce noise. The ADS7843 has a convientent PenIRQ pin to signal an actual touch or an Idle condition (x = -1,y = -1).

ADS7843Touchscreen.c

SHORT touchX,touchY;

void spistart(void)
{
    D_CS = 1;
    D_CLK = 1;
    D_DIN = 1;
}//end of spistart()

void ADS7843_write(unsigned char num)
{
    unsigned int count,mask,temp;
    int i;
    
    D_CLK = 0;
    mask = 0x80;

    for(count=0;count<8;count++)
    {
        temp = mask&num;
        if (temp == 0)    D_DIN = 0;
        else    D_DIN = 1;
        
        //D_DIN = temp>>(count);
        D_CLK = 0;
        
        for(i=0;i<5;i++)
        {
            Nop();
        }
  
        D_CLK = 1;
        for(i=0;i<5;i++)
        {
            Nop();
        }
        mask>>=1;
    }
}//end of ADS7843_write()


unsigned int ADS7843_read(void)
{
    unsigned int count;
    unsigned int num;
    int i;
    
    num = 0;
    for(count=0;count<12;count++)
    {    
        num<<=1;
        D_CLK = 1;
        for(i=0;i<5;i++)
        {
            Nop();
        }

        D_CLK = 0;
        for(i=0;i<5;i++)
        {
            Nop();
        }

        if(D_DOUT) num++;
     }
    return(num);
}//end of ADS7843_read()



void TouchInit(void)
{
    //Port Init
    D_CLK_TRIS = 0;
    D_CS_TRIS = 0;
    D_DIN_TRIS = 0;
    D_DOUT_TRIS = 1;
    D_IRQ_TRIS = 1;

    spistart();

}

void TouchGetXY(void)
{
    int i,count,x_set,y_set;
    int TP_X,TP_Y;    

    count =0;
    x_set = 0;
    y_set = 0;

    while(count<8)
    {
        //PORTAbits.RA1 = 1;
        //Delay1KTCYx(4);    //2ms delay (8MHz clk)

        D_CS = 0;
        ADS7843_write(0xd4);

        D_CLK = 1;
        for(i=0;i<5;i++)
        {
            Nop();
        }

        D_CLK = 0;
        for(i=0;i<5;i++)
        {
            Nop();
        }

        y_set = y_set + ADS7843_read();
        count++;
    }
    
    count = 0;
    while(count<16)
    {

        ADS7843_write(0x94);
    
        D_CLK = 1;
        for(i=0;i<5;i++)
        {
            Nop();
        }

        D_CLK = 0;
        for(i=0;i<5;i++)
        {
            Nop();
        }

        x_set = x_set + ADS7843_read();

        
        count++;
    }
    D_CS = 1;
    TP_X = x_set/16;
    TP_Y = y_set/8;

    touchX = .0925*TP_X-.0040*TP_Y-31.1315;    //X-coordinate
    touchY = .0006*TP_X+.0661*TP_Y-19.5759;        //Y-coordinate
}

SHORT TouchGetX(void)
{
    int x;
    x = touchX;
    return(x);
}

SHORT TouchGetY(void)
{
    int y;
    y = touchY;
    return(y);
}

int TouchIRQ(void)
{
    int temp;
    temp = D_IRQ;
    return(temp);
}


Those functions will interact with Microchip’s TouchGetMsg(), and only needs ads7843touchscreen.h included in the main .c file source.

  1. Add required main() code

A little bit of code needs to be added to the main() while loop, which is shown more than once in a Microchip app note. Also a data structure, GOL_MSG msg, to relay events needs to be cast.

So hopefully your project is going. Adding and interacting with the widgets is pretty straight forward and documented in the help file (you should have been there already). I had several issues along the way, such as:

  • The default font. Solution: use Font25 or Font35 and cast correctly.
  • Start with the newest version 3 something, drastic changes were made and things didn’t work.
  • While developing touch screen driver, the data wasn’t being transferred to the rest of the GOL, so the widgets wouldn’t draw as pushed. Solution: start new project completely with same drivers. ?????

CAN Code for Initialization

March 18, 2012 1 comment

Here’s some code to get going. The ECAN section of the 18F4580 datasheet describes the modules function and how to use it, so I’ll only briefly describe what’s going on.

To write to certain ECAN configuration registers, you must request to enter a Config mode, then wait for the module to enter it. The Baud rate settings are tricky, but can be found easily from here, Request form for CANopen Bit Timings. Only one Receive Filter is used and linked to Receive Buffer 0. To add more Enable the filter in RFCONx, associate to a Receive buffer with RXFBCONx, then set its identifier. Last is to exit the Config mode by requesting either Normal mode or Loopback mode for testing. An important point here is that the ECAN module won’t exit config mode unless the microcontroller is correctly connected to a CAN driver IC, even for going to Loopback mode.

void ECAN_Init(void)
{
    LATB = 0x00;
    TRISBbits.TRISB3 = 1;

    CANCON = 0x80;    //request CONFIG mode
    while(CANSTATbits.OPMODE2==0);

    ECANCON = 0x40;    //Sets ECAN to Mode 1

    BRGCON1 = 0x09;   //Sets Baud rate
    BRGCON2 = 0x84;
    BRGCON3 = 0x00;

    BSEL0 = 0xfc;

    RXM0EIDH = 0x00;    // 0's for EID and SID
    RXM0EIDL = 0x00;
    RXM0SIDH = 0xFF;    // Standard ID FILTER
    RXM0SIDL = 0xE0;    //Mask0 = 0x7ff

    RXFCON0 = 0x01;        //filter 0 enabled
    RXFCON1 = 0x00;        //all others disabled

    MSEL0 = 0xfc;        //Mask0 assigned to Filter0
    MSEL1 = 0xFF;        //all others no mask
    MSEL2 = 0xFF;
    MSEL3 = 0xFF;

    RXFBCON0 = 0x00;    //filter 0 assoc w/ RXB0, 1 w/ RXB1

    RXB0CONbits.RXM1 = 1;

    RXF0SIDH = 0x04;    //Recv Filter0 = 0x020
    RXF0SIDL = 0x00;    //Std. Identifier
    RXF0EIDH = 0x00;
    RXF0EIDL = 0x00;

    CANCON = 0x00;        //Set ECAN to normal mode
    //CANCON = 0x40;        //Set ECAN to Loopback mode(TEST)
    while(CANSTATbits.OPMODE2 == 1);    //wait till out of Config Mode
}//end of ECAN_Init()

When setting up a test bus, start with one node set in Loopback mode. In this mode, the acknowledge bits are ignored and allows the node to receive CAN messages transmitted from itself.This will confirm the baud and filter settings are correct. I made a loop of sending and receiving with counters, then displaying on an LCD(nokia 6100). Once I had my two breadboards able to send and receive the same number of messages, I connected them together. Of course the micrcontroller must be connected to a CAN driver IC, the MCP2551, with a 60Ω resistor connected between the CANH and CANL pins, or the module would never get out of config mode.

The datasheet describes how to transmit a message, and doesn’t need any extra configuration. To receive a message, the ECAN module will accept and place data in the proper register, then set a flag that can be polled. An interrupt can be used too.

Hopefully this helps get others going. Later.

New Router for CNC Machine

March 15, 2012 10 comments

Yay, Santa came through on the new router for Christmas, albeit a little late (he wasn’t sure what size I needed and was in my area on Santa business). It’s a Bosch 1HP palm router featuring a speed selection and detachable handle for a nice circular area to hold on to. Naturally, it was smaller than CNC router holder and the adapter for the other router.

New and old Routers.

I tried and failed at a complicated three-jawed system within the old adapter before getting new material. By chance, I found the same diameter PVC pipe, but with a thicker wall and made it work by cutting out an inch section and the pipe was able to close over the router body. A notch had to be cut on the bottom side to allow access to the shaft holding button (or whatever its called).

New router adapter.

All back together again.

The tool holder is squeezed pretty tight, so a new one may be the first project. Before that the table still needs to be milled flat, which I guess is the next step.

 

 

Categories: CNC Machine Tags:

THIS IS SpartaNode!

March 14, 2012 Leave a comment

I mean the prototype sensor node for my house CAN-bus, decked out in MSU colors. So with the exception of possibly the next node, no other circuit boards will have a theme or use primitive construction techniques.  The real sensor node will use a PIC18F2580 SOIC package, have a board less than 50cm square and use the shield concept swiped from an Arduino. At least that’s what I put together to have made by someone else. As a side note, I’d like to know what perf board would have hole spacing of √(.02)” to allow the screw terminals shown jammed in diagonally.

Since this 40-pin microcontroller is under-utilized, I’ll use it to test more nodes in the future. It was quicker to spend a day or so cutting, stripping and soldering wires than wait weeks for real circuit boards. This will at least allow me to start a test bus, even if it only has a couple nodes.

The next steps are software, and how to use the built in features of CAN smartly. A lot of this is already in spec form, like SAE-J1939 for heavy machinery that costs money all the way to OpenCAN that’s less money. These  schemes are more for systems that are time critical and people’s live being at risk. None of these are applicable to a normal house, so a new scheme can be developed. My goal is to release open source boards and basic code libraries for hackers and to provide design services for people who don’t think any of this is fun (weirdos).

K-Node

February 29, 2012 6 comments

Here’s the first permanent board for a node that is intended for the kitchen.The bell doesn’t work yet, but the rest of the circuit is there, including everyone’s favorite feature, a clock! This is a copy of the breadboard Node #2 and its program, so just receives the message from Node #1, but not the sensor reading. The RTC is provided by the DS1305 to the right of the PIC and uses the crystal hidden inside the blue shrink tube below (it was an SMD part).

The K-Node

K-Node Circuit

Since this circuit is going up on the wall, I tried to make it look nice. The paint scheme is all the 99¢ spray variety as usual, gloss black for the piece of pine board and flat black for the perf board. To hold the LCD, I drilled undersized pockets (about the width of the flats) for the #4 nuts and stamped the hex with a rubber mallet and punch. After painting they were glued in with superglue. The circuit board and bell is similar, but are size #6 and the nuts are on the bottom.

Circuit board mountings.

The bell seems original to my house, but was terrible sounding when I first bought the place. I though it was wall papered over, but was just painted close to a hundred times. Once I stripped off the paint it rang instead of clattered. It rings fine from a nice beefy power supply, but sagged the puny wall wart and browns out the microcontroller. Guh, so I’ll have to get real readings and shit to get that going. Anyways, here’s what is looks like inside.

Bell guts.

So this concludes the physical portion of the design. The MCP2551 and the ECAN engine in the PIC18F4580 takes care of that for the most part. So now I’m on to software development.