PIC24FJ interfacing with MLX90316 - Page 1
Forum section: electronics / general

author: raphaeldavidf
author_rank: Contributor
timestamp: April 28, 2015, 10:33:59 pm
content: Hey guys,I'm really stuck with this problem and don't know what else to tryI'm trying to read the MLX90316 rotary position sensor, SPI version, with a PIC24FJ64GA004 and I'm getting nothing out.I was successful reading it with a PIC16F628A, so the MLX is working.This is the code that I used with the PIC16F628ACode:#include <16F628A.h>#use delay(clock=8000000)#fuses NOWDT, NOPROTECT, BROWNOUT, NOMCLR, NOCPD, HS/* FUSES for crystal */#use fast_io(ALL)#use rs232(BAUD=9600, XMIT=PIN_B7, RCV=PIN_B0, BITS=8, PARITY=N, ERRORS)#define PIN_MXSXPIN_B1/* MOSI (Master out slave in) and MISO (Master in slave out) pin*/#define PIN_SCLKPIN_B2/* Clock pin */#define PIN_SSBPIN_B3/* Slave select pin */#define MOSI0b00000001#define MISO0b00000011unsigned long data_transmission(unsigned int tx) {unsigned int rx = 0;for (int i = 0; i < 8; i++) {set_tris_b(MOSI);/* MXSX pin as MOSI */if ((tx & 1) != 0)/* If first bit is set */output_high(PIN_MXSX);/* Send 1 */elseoutput_low(PIN_MXSX);/* Else send 0 */output_high(PIN_SCLK);/* Rising edge (slave get data) */tx = tx >> 1;/* Next bit */set_tris_b(MISO);/* MXSX pin as MISO */rx = rx << 1;/* Open space for next bit */output_low(PIN_SCLK);/* Falling edge (slave send data) */if (input(PIN_MXSX) == 1)/* If received bit is 1 set that bit on rx */rx = rx | 1;}return rx;}unsigned long get_angle() {unsigned int bt = 0;unsigned long aux = 0;unsigned int32 output = 0;/* int32 because of multipication by 3600 */output_low(PIN_SSB);/* Turn on slave */data_transmission(0x55);/* Send 0x55, get 0xFF */data_transmission(0xFF);/* Send 0xFF, get 0xFF */bt = data_transmission(0xFF);/* Send 0xFF, get data most significant byte */aux = bt << 8;/* Shitf left to add the less significant byte */bt = data_transmission(0xFF);/* Send 0xFF, get data less significant byte */aux = aux + bt;/* assembly data */if ((aux & 3) == 1) {/* If is not an error (first two bits set) */aux = aux >> 2;/* Discart first two bits */output = (int32)aux * 225 / 1024;/* Conversion 3600 / 16384*/}output_high(PIN_SSB);/* Turn off slave */return output;}void main(void) {set_tris_a(0b00000000);/* No input */set_tris_b(0b00000001);/* B0 as input */output_a(0x00);output_b(0x00);while (TRUE) {unsigned long aux;aux = get_angle();printf("%lu\n", aux);delay_ms(100);}}The working.png show the working communication from the PIC16F628A.Now with the PIC24FJ I'm using the TXB0108 voltage level translator to convert the 3.3v from the pic to 5v for the MLX(see pic24fj.png for schematic).I'm using this code for the PIC24Fj, I had to put some delay_us to account for the difference in clock speed:Code:#include <24FJ64GA004.h>#fuses FRC_PLL, NOJTAG, NODEBUG, NOWDT, NOPROTECT#use delay(clock=32M, internal)//#use fast_io(all)#pin_select U1RX=PIN_B10#pin_select U1TX=PIN_B11#use rs232(baud=9600, UART1, bits=8, parity=N, DISABLE_INTS, errors)#define PIN_MXSXPIN_C6/* MOSI (Master out slave in) and MISO (Master in slave out) pin*/#define PIN_SCLKPIN_B9/* Clock pin */#define PIN_SSBPIN_C9/* Slave select pin */#define MOSI0b0000000000000000#define MISO0b0000000001000000unsigned long data_transmission(unsigned int tx) {unsigned int rx = 0;delay_us(40);for (int i = 0; i < 8; i++) {set_tris_c(MOSI);/* MXSX pin as MOSI */if ((tx & 1) != 0)/* If first bit is set */output_high(PIN_MXSX);/* Send 1 */elseoutput_low(PIN_MXSX);/* Else send 0 */delay_us(1);output_high(PIN_SCLK);/* Rising edge (slave get data) */tx = tx >> 1;/* Next bit */rx = rx << 1;/* Open space for next bit */delay_us(10);set_tris_c(MISO);/* MXSX pin as MISO */output_low(PIN_SCLK);/* Falling edge (slave send data) */if (input(PIN_MXSX) == 1)/* If received bit is 1 set that bit on rx */rx = rx | 1;delay_us(10);}return rx;}unsigned long get_angle() {unsigned int bt = 0;unsigned long aux = 0;unsigned int32 output = 0;/* int32 because of multipication by 3600 */output_low(PIN_SSB);/* Turn on slave */delay_us(10);data_transmission(0x55);/* Send 0x55, get 0xFF */data_transmission(0xFF);/* Send 0xFF, get 0xFF */bt = data_transmission(0xFF);/* Send 0xFF, get data most significant byte */aux = bt << 8;/* Shitf left to add the less significant byte */bt = data_transmission(0xFF);/* Send 0xFF, get data less significant byte */aux = aux + bt;/* assembly data */if ((aux & 3) == 1) {/* If is not an error (first two bits set) */aux = aux >> 2;/* Discart first two bits */output = (int32)aux * 225 / 1024;/* Conversion 3600 / 16384*/}output_high(PIN_SSB);/* Turn off slave */return output;}void main(void) {set_tris_a(0x0);/* output */set_tris_b(0x0);/* output */set_tris_c(0x0);/* output */output_a(0);/* 0 */output_b(0);/* 0 */output_c(0);/* 0 */output_high(PIN_B8);/* activate TXB0108 */while (TRUE) {unsigned long aux;aux = get_angle();printf("%lu\n", aux);delay_ms(500);}}and the not_working_no_mlx.png is what I'm getting without the MLX connected, so I know that the PIC is doing what it is supposed to do.The problem is when I connect the MLX, as shown in not_working_with_mlx.png.If anyone can give me some helpThanks

author: Unknown
author_rank: Unknown
timestamp: April 28, 2015, 11:21:33 pm
content: In the schematic you posted you don't have a pull-up on MCLR.What compiler are you using? Are you correctly configuting the interal clock?

author: raphaeldavidf
author_rank: Contributor
timestamp: April 28, 2015, 11:34:10 pm
content: Quote from: exapod on April 28, 2015, 11:21:33 pmSchematic updated!I'm using CCS C compiler, and the internal clock is correct because the serial communication is working ok

author: 22swg
author_rank: Frequent Contributor
timestamp: April 29, 2015, 08:56:36 am
content: I would suggest your 10k pullup (and reset switch) is the wrong end of the mclr resistor ....edit The oscillator config seems short of code, you set FRC_PLL , but then don't set the PLL and the switch over... You could be running at FRC ...

author: hans
author_rank: Super Contributor
timestamp: April 29, 2015, 11:41:20 am
content: I would consider rethinking the use of TXB0108. In your third pic there looks to be some kind of oscillation on the data pins; and usually that's the failure of the "Auto Direction sense" feature.I've seen it being used in an OEM module before, on a standard serial port (1.8V > 3.3V conversion). The serial TX pin from the module was oscillation at 3MHz or so, because apparently it could not figure out which direction the data was flowing (especially when you use low-value pull-ups).Maybe use I2C-style connections to the PIC instead: pick a 5V tolerant pin, pull-up to 5V and use open-drain outputs on the PIC. If you read the MLX sensor datasheet closely, it suggests it's also using open-drain pins. In that case it's entirely safe to do so.

author: raphaeldavidf
author_rank: Contributor
timestamp: April 29, 2015, 12:52:55 pm
content: Quote from: 22swg on April 29, 2015, 08:56:36 amHey 22swg, thanks for the help, but I don't think that's the problem. The pic is resetting ok, and the clock looks fine: the delay_ms is timing right and the serial communication(TX and RX) is working fine. I also looked at the CCS manual and didn't find any code to add to enable the PLL:Code:If the internal oscillator fuse option are specified in the #fuses and a valid clock is specified inthe #use delay(clock=xxx) directive the compiler automatically sets up the oscillator.Do you know any other code that I should add to make it work?Thanks a lot!

author: raphaeldavidf
author_rank: Contributor
timestamp: April 29, 2015, 01:29:00 pm
content: Quote from: hans on April 29, 2015, 11:41:20 amHey hans, thanks for the help!Do you think that a pullup on the MLX side would make it easier for the auto direction sense to work? I already had the pic board made, so its easier to change the MLX board, and I would reallyyy like to keep this board.When I was laying out the board I saw that I2C-style connection in the datasheet and I thought it was only needed if you use a SPI master that have separated MISO and MOSI pins :/

author: 22swg
author_rank: Frequent Contributor
timestamp: April 29, 2015, 02:59:39 pm
content: I struggled with PIC24EP512GU810 PLL and had to output REFOSC to a pin and frequency counter to debug settings so without hands on with your particular PIC24FJ or CCS this is what is usually required after setting config FRCPLL first code in main(), obviously device dependent...Edit your "#fuses FRC_PLL," may do the extra osc settingsCode:// FOSCSEL#pragma config FNOSC = FRCPLL // Initial Oscillator Source Selection bits (Internal Fast RC with PLL (FRCPLL))#pragma config IESO = ON // Two-speed Oscillator Start-up Enable bit (Start up device with FRC, then switch to user-selected oscillator source)// Configure PLL prescaler, PLL postscaler, PLL divisorint main(void) {PLLFBD = 65; // M=65CLKDIVbits.PLLPOST = 2; // N2=2CLKDIVbits.PLLPRE = 3; // N1=3// Initiate Clock Switch to FRC oscillator with PLL (NOSC=0b001)__builtin_write_OSCCONH(0x01);__builtin_write_OSCCONL(OSCCON | 0x03); // ENable Switch and sec osc RTCC// Wait for Clock switch to occurwhile (OSCCONbits.COSC != 0b001);// Wait for PLL to lockwhile (OSCCONbits.LOCK != 1);// Initialize devices

author: raphaeldavidf
author_rank: Contributor
timestamp: April 30, 2015, 12:16:06 am
content: Quote from: 22swg on April 29, 2015, 02:59:39 pmJust tried a simple test code with an infinite loop that toggles a pin and got the right clock, so I think that CCS do all that stuff

author: raphaeldavidf
author_rank: Contributor
timestamp: April 30, 2015, 12:36:36 am
content: I think that I found out the problem:Quotefrom this pdf :http://www.adafruit.com/datasheets/txb0108appnote.pdfI just wish that this important piece of info were better displayed in the datasheetSo I measured the capacitance of each MLX pin, relative to ground and this is what I got:CS: 39 pFSCLK: 7 nFMXSX: 7 nFand then I measured the TX and RX pins from my serial to usb converter:TX: 25 pFRX: 28 pFAll that explains why the serial works, and why I don't get that oscillation on the CS/Enable pin.So my problem now is: how can I make that capacitance lower?? Or at least minimize its effectAny ideas?

author: 22swg
author_rank: Frequent Contributor
timestamp: April 30, 2015, 08:35:15 am
content: Just to confirm my PLL settings. the example I gave would give about Fosc 16Mhz 8 MIPS On a PIC24EP ( toggle a pin timing will depend very much on code ? )

author: raphaeldavidf
author_rank: Contributor
timestamp: April 30, 2015, 06:22:01 pm
content: Quote from: mojo-chan on April 30, 2015, 10:22:41 amHey mojo-chan, thanks for the help but I don't think thats the problem because I'm using the same timing I used with the PIC16F628A and it worked ok.