Hey all,
I have been having one heck of a day trying to interface between my PIC32MX120F064H and a cheap NRF24L01 module I grabbed off ebay. I have configured the SPI module, and am able to send out any data I want, but I am not able to read any data back from the chip. I am using the PicKit 3 as a programmer, and I am using XC32 free for compiling.
I have finished setting up the SPI, and to test that it works I decided to send a NOP to the NRF (0b11111111), which, according to the data sheet, should return the content of the STATUS register of the chip. I do this with the following 4 lines in NRF.c:
ncsn = 0;
test = SPI_trans(SPI3, 0b11111111);
test = SPI_trans(SPI3, 0x00);
ncsn = 1;
to check the content of the test variable, I have setup breakpoints on "test = SPI_trans(SPI3, 0b11111111);", "test = SPI_trans(SPI3, 0x00);" , and one on "ncsn = 1;":
However, no matter at what point I am, the test variable remains at 0:
I am however, quite sure that the chip is responding, as there is a signal present on the MISO line. Here is a picture of the signal without stopping at the breakpoints:
Trace 1: MOSI
Trace 2: MISO
Traco 3: SCK
I have checked that stopping between the two packets with a breakpoint does not change the signal with the oscilloscope.
Currently I am using the PICKIT to power the circuit as I do not have acces to my powersupply. Ill test it with external as soon as I am able to.
Can anyone help me out? Any help is appreciated.
Here is the code:
Main File:
#include <stdio.h>
#include <stdlib.h>
#include <p32xxxx.h>
#include <xc.h>
#include "config.h"
#include "NRF.h"
void init_IO();
void shake_NRF();
int main(int argc, char** argv) {
init_IO();
//TESTING SPI
shake_NRF();
}
void init_IO() {
//Disable JTAG as it conflicts with some of the pins
CFGCONbits.JTAGEN = 0;
//NRF SPI:
ANSELA = 0x0000;
TRISBbits.TRISB9 = 1; //MISO
SDI3Rbits.SDI3R = 0b0101;
TRISBbits.TRISB10 = 0; //MOSI
RPB10Rbits.RPB10R = 0b1110;
TRISBbits.TRISB13 = 0; //CE
TRISBbits.TRISB14 = 0; //SCK
TRISBbits.TRISB15 = 0; //CSN
}
void shake_NRF() {
NRF_init(100);
}
config.h:
#ifndef CONFIG_H
#define CONFIG_H
#ifdef __cplusplus
extern "C" {
#endif
#include <p32xxxx.h>
#include <xc.h>
typedef unsigned char BOOL;
#define TRUE 1
#define FALSE 0
// ======== GLOBAL OPTIONS ==========
//System clock frequency
#define F_OSC 48000000
//Peripheral Clock Divider
#define F_PER_DIV 8
//Peripheral Clock frequency
#define F_PER F_OSC/F_PER_DIV
#ifdef __cplusplus
}
#endif
#endif /* CONFIG_H */
config.c:
// DEVCFG3
// USERID = No Setting
#pragma config PMDL1WAY = OFF // Peripheral Module Disable Configuration (Allow multiple reconfigurations)
#pragma config IOL1WAY = OFF // Peripheral Pin Select Configuration (Allow multiple reconfigurations)
// DEVCFG2
#pragma config FPLLIDIV = DIV_2 // PLL Input Divider (2x Divider)
#pragma config FPLLMUL = MUL_24 // PLL Multiplier (24x Multiplier)
#pragma config FPLLODIV = DIV_2 // System PLL Output Clock Divider (PLL Divide by 2)
// DEVCFG1
#pragma config FNOSC = FRCPLL // Oscillator Selection Bits (Fast RC Osc with PLL)
#pragma config FSOSCEN = OFF // Secondary Oscillator Enable (Disabled)
#pragma config IESO = OFF // Internal/External Switch Over (Disabled)
#pragma config POSCMOD = HS // Primary Oscillator Configuration (HS osc mode)
#pragma config OSCIOFNC = OFF // CLKO Output Signal Active on the OSCO Pin (Disabled)
#pragma config FPBDIV = DIV_8 // Peripheral Clock Divisor (Pb_Clk is Sys_Clk/8)
#pragma config FCKSM = CSDCMD // Clock Switching and Monitor Selection (Clock Switch Disable, FSCM Disabled)
#pragma config WDTPS = PS1048576 // Watchdog Timer Postscaler (1:1048576)
#pragma config WINDIS = OFF // Watchdog Timer Window Enable (Watchdog Timer is in Non-Window Mode)
#pragma config FWDTEN = OFF // Watchdog Timer Enable (WDT Disabled (SWDTEN Bit Controls))
#pragma config FWDTWINSZ = WINSZ_25 // Watchdog Timer Window Size (Window Size is 25%)
// DEVCFG0
#pragma config JTAGEN = OFF // JTAG Enable (JTAG Disabled)
#pragma config ICESEL = ICS_PGx2 // ICE/ICD Comm Channel Select (Communicate on PGEC2/PGED2)
#pragma config PWP = OFF // Program Flash Write Protect (Disable)
#pragma config BWP = OFF // Boot Flash Write Protect bit (Protection Disabled)
#pragma config CP = OFF // Code Protect (Protection Disabled)
SPI.h:
#ifndef SPI_H
#define SPI_H
#ifdef __cplusplus
extern "C" {
#endif
#include "config.h"
/*
* ========= Structures and Enums =========
*/
typedef enum {
SPI_INITF_FRM_EN = 0x80000000,
SPI_INITF_FRMSYNC_EN = 0x40000000,
SPI_INITF_FRMPOL_ACTH = 0x20000000,
SPI_INITF_FRMPOL_ACTL = 0x0,
SPI_INITF_SPIFE_CO = 0x20000,
SPI_INITF_SPIFE_PRE = 0x0,
SPI_INITF_FRZ = 0x4000,
SPI_INITF_SIDL = 0x2000,
SPI_INITF_DISSDO = 0x1000,
SPI_INITF_MODE_8 = 0x0,
SPI_INITF_MODE_16 = 0x400,
SPI_INITF_MODE_32 = 0x800,
SPI_INITF_SMP_END = 0x200,
SPI_INITF_SMP_MID = 0x0,
SPI_INITF_CKE_ACTIVE_TO_IDLE = 0x100,
SPI_INITF_CKE_IDLE_TO_ACTIVE = 0x0,
SPI_INITF_SSEN = 0x80,
SPI_INITF_CKP_IDLE_IS_LO = 0x40,
SPI_INITF_CKP_ACTI_IS_HI = 0x40,
SPI_INITF_CKP_IDLE_IS_HI = 0x0,
SPI_INITF_CKP_ACTI_IS_LO = 0x0,
SPI_INITF_MSTEN = 0x20,
SPI_INITF_MASTER = 0x20,
SPI_INITF_SLAVE = 0x0
} SPI_INITF;
typedef enum {
SPI1 = 1,
SPI2 = 2,
SPI3 = 3
} SPI_CHANNEL;
/*
* ======= Functions =======
*/
void SPI_init(SPI_CHANNEL, SPI_INITF, int baud);
int SPI_trans(SPI_CHANNEL, int data);
#ifdef __cplusplus
}
#endif
#endif /* SPI_H */
SPI.c:
#include "config.h"
#include <xc.h>
void SPI_init(SPI_CHANNEL channel, SPI_INITF flag, int baud) {
//Calc Prescalar for Baud
int prsclr;
prsclr = F_PER / baud / 2 - 1;
if (prsclr < 1 || prsclr > 512) {
while (1) {
//Prescalar too large/small
__asm__("nop");
}
} else {
//Available Prescalar. Continue:
if (channel == SPI1) {
__asm__("nop"); //Just to be sure
SPI1CONbits.ON = 0; //Disable SPI
__asm__("nop"); //Nop as SFR should not be accesed 1 cycle after ON clear
SPI1BUF = 0; //Clear Buffer
SPI1BRG = prsclr;
SPI1CON = flag; //Setup options determined by flags
SPI1CONbits.ENHBUF = 1;
__asm__("nop"); //Just to be sure
SPI1CONbits. ON = 1;
__asm__("nop"); //Just to be sure
} else if (channel == SPI2) {
__asm__("nop"); //Just to be sure
SPI2CONbits.ON = 0; //Disable SPI
__asm__("nop"); //Nop as SFR should not be accesed 1 cycle after ON clear
SPI2BUF = 0; //Clear Buffer
SPI2BRG = prsclr;
SPI2CON = flag; //Setup options determined by flags
SPI2CONbits.ENHBUF = 1;
__asm__("nop"); //Just to be sure
SPI2CONbits. ON = 1;
__asm__("nop"); //Just to be sure
} else if (channel == SPI3) {
__asm__("nop"); //Just to be sure
SPI3CONbits.ON = 0; //Disable SPI
__asm__("nop"); //Nop as SFR should not be accesed 1 cycle after ON clear
SPI3BUF = 0; //Clear Buffer
SPI3BRG = prsclr;
SPI3CON = flag; //Setup options determined by flags
SPI3CONbits.ENHBUF = 1;
__asm__("nop"); //Just to be sure
SPI3CONbits. ON = 1;
__asm__("nop"); //Just to be sure
}
}
}
int SPI_trans(SPI_CHANNEL channel, int data) {
if (channel == SPI1) {
if (SPI1STATbits.SPIRBF) {
int temp = (char) SPI1BUF;
}
SPI1BUF = data;
while (SPI1STATbits.SPIBUSY) {
__asm__("nop");
}
return SPI1BUF;
} else if (channel == SPI2) {
if (SPI2STATbits.SPIRBF) {
int temp = (char) SPI2BUF;
}
SPI2BUF = data;
while (SPI2STATbits.SPIBUSY) {
__asm__("nop");
}
return SPI2BUF;
} else if (channel == SPI3) {
if (SPI3STATbits.SPIRBF) {
int temp = (char) SPI3BUF;
}
SPI3BUF = data;
while (SPI3STATbits.SPIBUSY) {
__asm__("nop");
}
__asm__("nop");
return SPI3BUF;
} else {
//?
while (1) {
__asm__("nop");
}
}
}
NRF.h:
#define NRF_H
#ifdef __cplusplus
extern "C" {
#endif
#include "SPI.h"
#include "config.h"
#include <xc.h>
// ====== Commands ========
#define NRF_CMD__R_REGISTER 0b00000000
#define NRF_CMD__W_REGISTER 0b00100000
#define NRF_CMD__R_RX_PAYLOAD 0b01100000
#define NRF_CMD__W_TX_PAYLOAD 0b10100000
#define NRF_CMD__FLUSH_TX 0b11100001
#define NRF_CMD__FLUSH_RX 0b11100010
#define NRF_CMD__REUSE_TX_PL 0b11100011
#define NRF_CMD__ACTIVATE 0b01010000
#define NRF_CMD__R_RX_PL_WID 0b01100000
#define NRF_CMD__W_ACK_PAYLOAD 0b10101000
#define NRF_CMD__W_TX_PAYLOAD_NO_ACK 0b10110000
#define NRF_CMD__NOP 0b11111111
// ====== Registers =======
#define NRF_RG__CONFIG 0x00
#define NRF_RG__EN_AA 0x01
#define NRF_RG__EN_RXADDR 0x02
#define NRF_RG__SETUP_AW 0x03
#define NRF_RG__SETUP_RETR 0x04
#define NRF_RG__RF_CH 0x05
#define NRF_RG__RF_SETUP 0x06
#define NRF_RG__STATUS 0x07
#define NRF_RG__OBSERVE_TX 0x08
#define NRF_RG__CD 0x09
#define NRF_RG__RX_ADDR_P0 0x0A
#define NRF_RG__RX_ADDR_P1 0x0B
#define NRF_RG__RX_ADDR_P2 0x0C
#define NRF_RG__RX_ADDR_P3 0x0D
#define NRF_RG__RX_ADDR_P4 0x0E
#define NRF_RG__RX_ADDR_P5 0x0F
#define NRF_RG__TX_ADDR 0x10
#define NRF_RG__RX_PW_P0 0x11
#define NRF_RG__RX_PW_P1 0x12
#define NRF_RG__RX_PW_P2 0x13
#define NRF_RG__RX_PW_P3 0x14
#define NRF_RG__RX_PW_P4 0x15
#define NRF_RG__RX_PW_P5 0x16
#define NRF_RG__FIFO_STATUS 0x17
#define NRF_RG__DYNPD 0x1C
#define NRF_RG__FEATURE 0x1D
void NRF_init(char channel);
#define nce LATBbits.LATB13
#define ncsn LATBbits.LATB15
#define ADDRESS0 0b00101011
#define ADDRESS1 0b00101011
#define ADDRESS2 0b00101011
#ifdef __cplusplus
}
#endif
#endif /* NRF_H */
NRF.c:
char test;
void NRF_init(char channel) {
int x;
for (x = 0; x < 100; x++) {
__asm__("nop");
}
//Active SPI module with corrct edge, mode, phase etc
SPI_init(SPI3,
SPI_INITF_MASTER |
SPI_INITF_MODE_8 |
SPI_INITF_CKE_ACTIVE_TO_IDLE /*|
SPI_INITF_SMP_END*/
, 9600);
ncsn = 1;
nce = 1;
ncsn = 0;
test = SPI_trans(SPI3, 0b11111111);
test = SPI_trans(SPI3, 0x00);
ncsn = 1;
}