Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

PIC12F SPI Staying On for too long

Status
Not open for further replies.

Overclocked

Member
Im diving into the world of C again, and Im using XC8 with a 12F1840. Im using the SPI module to interface to a WS2801 chip (its a RGB controller). Dont worry, Ive figured out all the issues from last time and switched to this controller (because its what I'll be using). The data format the controller needs is in the form of Red, Green, and Blue. 8 Bits for each color, so 24 bits total. I got SPI working but I noticed that during writing it stays on for too long. The SPI clock is at 2Mhz (measured) and gives 8 clock pulses. Nothing too unusual there, But when Im writing a byte, it stays on for a total of 12uS. I compared the two, and its sending data for far longer than 8 clock pulses. It looks like its sending data for almost 16 clock pulses instead of 8.

Datasheet for WS2801
https://www.adafruit.com/datasheets/WS2801.pdf

There isnt much to actually sending out data (its dead simple). What the code Should do is just light up the Red LED, instead it lights up both Red and Green. I have a suspicion its not waiting for the buffer to be empty before sending data. For now Im testing individual colors.

Main Code
C:
#include "mcc_generated_files/mcc.h"
#include "../xc.h"
#include "build/../pic12f1840.h"
#define _XTAL_FREQ 8000000 //8Mhz
//unsigned char pData;
//unsigned char SPI_Write;

void SPI_Initialize(void) {
  // Set the SPI module to the options selected in the User Interface

  // BF RCinprocess_TXcomplete; UA dontupdate; SMP Sample At Middle; P stopbit_notdetected; S startbit_notdetected; R_nW write_noTX; CKE Idle to Active; D_nA lastbyte_address;
  SSP1STAT = 0x00;

  // SSPEN enabled; WCOL no_collision; SSPOV no_overflow; CKP Idle:Low, Active:High; SSPM FOSC/4;
  SSP1CON1 = 0x20;

  // SSPADD 0;
  SSP1ADD = 0x00;
}

void SPI_Write(unsigned char pData){ //Write to the SSP buffer.
  SSP1BUF = pData;
  while(!SSPSTATbits.BF);
}

void main(void) {
  // initialize the device
  SYSTEM_Initialize();
  SPI_Initialize();

  while (true) {
  SPI_Write (0xFF);
  SPI_Write (0x00);
  SPI_Write (0x00);
   
   
   
   
   
  }
}

mcc.h. Yes I used the code configurator. Just was curious to see what it did.

C:
// Configuration bits: selected in the GUI

// CONFIG1
#pragma config IESO = ON  // Internal/External Switchover->Internal/External Switchover mode is enabled
#pragma config BOREN = ON  // Brown-out Reset Enable->Brown-out Reset enabled
#pragma config PWRTE = OFF  // Power-up Timer Enable->PWRT disabled
#pragma config FOSC = INTOSC  // Oscillator Selection->INTOSC oscillator: I/O function on CLKIN pin
#pragma config FCMEN = ON  // Fail-Safe Clock Monitor Enable->Fail-Safe Clock Monitor is enabled
#pragma config MCLRE = OFF  // MCLR Pin Function Select->MCLR/VPP pin function is digital input
#pragma config CP = OFF  // Flash Program Memory Code Protection->Program memory code protection is disabled
#pragma config CPD = OFF  // Data Memory Code Protection->Data memory code protection is disabled
#pragma config WDTE = OFF  // Watchdog Timer Enable->WDT disabled
#pragma config CLKOUTEN = OFF  // Clock Out Enable->CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin

// CONFIG2
#pragma config WRT = OFF  // Flash Memory Self-Write Protection->Write protection off
#pragma config LVP = OFF  // Low-Voltage Programming Enable->High-voltage on MCLR/VPP must be used for programming
#pragma config STVREN = ON  // Stack Overflow/Underflow Reset Enable->Stack Overflow or Underflow will cause a Reset
#pragma config PLLEN = OFF  // PLL Enable->4x PLL disabled
#pragma config BORV = LO  // Brown-out Reset Voltage Selection->Brown-out Reset Voltage (Vbor), low trip point selected.

#include "mcc.h"

void SYSTEM_Initialize(void) {
  OSCILLATOR_Initialize();
  PIN_MANAGER_Initialize();
  SPI_Initialize();
}

void OSCILLATOR_Initialize(void) {
  // SPLLEN disabled; SCS INTOSC; IRCF 8MHz_HF;
  OSCCON = 0x72;
  // OSTS intosc; HFIOFR disabled; HFIOFS not0.5percent_acc; PLLR disabled; T1OSCR disabled; MFIOFR disabled; HFIOFL not2percent_acc; LFIOFR disabled;
  OSCSTAT = 0x00;
  // TUN 0x0;
  OSCTUNE = 0x00;
  // Set the secondary oscillator

}
 
I think you need to sample at the SCK rising edge to that would be CKE high (bit 6 of SSP1STAT) , CKP low (bit 4 of SSP1CON1)
 
But when Im writing a byte, it stays on for a total of 12uS.
C:
  while (true) {
  SPI_Write (0xFF);
  SPI_Write (0x00);
  SPI_Write (0x00);
  }

Are you sure you are timing just a single byte? It probably isn't coincidental that 3 bytes at 2MHz should take 12us.

The interface section of the datasheet for the WS2801 is poorly written but it appears that the device will latch gray scale data once the CLK line has been low for 500us. Since your while loop runs constantly, you never give the WS2801 a chance to latch in the data you are shifting into it. Add a delay larger than 500us after your third SPI_Write() and see if that makes any difference.
 
In your SPI_Write routine, after you detect BF then read the SSP1BUF to clear the BF flag. You can throw it away, but do the read
Code:
void SPI_Write(unsigned char pData){ //Write to the SSP buffer.
  SSP1BUF = pData;
  while(!SSPSTATbits.BF);
  pData = SSP1BUF;      // reading SSPBUF clears BF for next time
}
 
In your SPI_Write routine, after you detect BF then read the SSP1BUF to clear the BF flag. You can throw it away, but do the read
Code:
void SPI_Write(unsigned char pData){ //Write to the SSP buffer.
  SSP1BUF = pData;
  while(!SSPSTATbits.BF);
  pData = SSP1BUF;      // reading SSPBUF clears BF for next time
}
This helped a lot as I was having trouble outputting White colors (ie increasing R,G,B together). What also helped was setting the clock to idle High. Strange, but its what got it to work with no trouble.
 
Status
Not open for further replies.

Latest threads

Back
Top