Chip:C8051F321 & PCF85176(LCD Driver)
I am trying to communicate from C8051F321(MASTER) to PCF85176(SLAVE), and the original code is only transmit for one byte like this:
START → SLAVE ADDR → DATA → ACK → STOP
But I tried to make it like
START → SLAVE ADDR → Command → ACK → DATA → ACK...→ ACK ..→ ACK .. →
STOP
And it always no effect like my code
How can I correct my code?
Thanks for helping~
void SMBus_ISR (void) interrupt 7
{
bit FAIL = 0; // Used by the ISR to flag failed
// transfers
static bit ADDR_SEND = 0; // Used by the ISR to flag failed
unsigned char a; // transmissions as slave addresses
if(ARBLOST == 0)
{
switch (SMB0CN & 0xF0) // Status vector
{
// Master Transmitter/Receiver: START condition transmitted.
case SMB_MTSTA:
SMB0DAT = TARGET; // Load address of the target slave
SMB0DAT &= 0xFE; // Clear the LSB of the address for the
// R/W bit
SMB0DAT |= SMB_RW; // Load R/W bit
STA = 0; // Manually clear START bit
ADDR_SEND = 1;
break;
// Master Transmitter: Data byte
case SMB_MTDB:
if (ACK) // Slave Address or Data Byte
{ // Acknowledged?
if (ADDR_SEND)
{
ADDR_SEND = 0; // Next byte is not a slave address
if(SMB_DATA_OUT==0xF0)
{
SMB0DAT = SMB_DATA_OUT;
ADDR_SEND = 0;
}
else
{
SMB0DAT = SMB_Command_OUT;
ADDR_SEND = 1;
}
}
else // If previous byte was not a slave address,
{
STO =1; // Set STO to terminate transfer
SMB_BUSY =0; // And free SMBus interface
}
}
else
{
STO = 1; // Set STO to terminate transfer
STA = 1; // By a START
NUM_ERRORS++; // Indicate error
}
break;
//Master Receiver:byte received
case SMB_MRDB:
SMB_DATA_IN =SMB0DAT; // Store received byte
SMB_BUSY = 0; // Free SMBus interface
ACK = 0; // Send NACK to indicate last byte
// of this transfer
STO = 1; // Send STOP to terminate transfer
break;
default:
FAIL = 1; // Indicate failed transfer
// and handle at end of ISR
break;
}//end switch
}
else
{
//ARBLOST = 1,error occurred...abort transmission
FAIL = 1;
} //end ARBLOST if
if(FAIL) // If the transfer failed,
{
SMB0CF &= ~0x80; // Reset communication
SMB0CF |= 0x80;
STA = 0;
STO = 0;
ACK = 0;
SMB_BUSY = 0; // Free SMBus
FAIL = 0;
NUM_ERRORS++; // Indicate an error occurred
}
SI = 0; //Clear interrupt flag
}
Related
I've got a problem with PEC on STM32 SMBUS, which i use to read data from a MLX90614 IR thermometer. When i start the device, either the PECERR flag is set and continues to be set, for all transmissions, even though the data from the IR thermometer seems to be correct. Or the PECERR is never set and all the data from the IR thermometer is still correct.
When i study the data on my oscilloscope i can see no difference between the signals when the PECERR is set or not. As stated earlier data seems to be good either way.
I could of course just ignore the PECERR flag, but i'd lige to be able to filter out any eventual garbled transmissions. Anyone have an idea what i am doing wrong here?
void I2C_SMBUS_Initialize(I2C_TypeDef *h) {
h->CR2 &= ~I2C_CR2_FREQ; // Clear frequency part of register
h->CR2 |= 0x8; // Clock speed in Mhz
h->OAR1 = 0x4000;
h->CCR = 0;
h->CCR &= ~I2C_CCR_DUTY;
h->CCR |= 0x190;
h->TRISE &= ~I2C_TRISE_TRISE; // Clear TRISE bits
h->TRISE |= 0x9; // Set TRISE
h->CR1 |= I2C_CR1_ENPEC; // Enable packet error check
h->CR1 |= I2C_CR1_SMBTYPE; // SMBUS host
h->CR1 |= I2C_CR1_SMBUS; // SMBUS Mode
h->CR1 |= I2C_CR1_PE; // Start i2c
}
uint16_t I2C_SMBUS_ReadWord(I2C_TypeDef* h, uint8_t deviceAddress, uint8_t command) {
static const uint16_t ERROR_CODE = 0x3BFF;
//static const uint8_t deviceAddress = 0x5A;
static const uint8_t timeout = 100;
uint16_t temp = 0;
h->CR1 &= ~I2C_CR1_POS;
// Generate start bit
sendStartBit(h);
// Wait for start bit set
if (!waitFlag((&h->SR1), I2C_SR1_SB, BIT_SET, timeout)) {
DEBUG_PUTS("Timeout while waiting for start bit set");
return ERROR_CODE;
}
// Address byte. 7 bit. Shifted one lefet
sendAddress(h, deviceAddress, I2C_WRITE);
// Wait for address bit set
if (!waitFlag((&h->SR1), I2C_SR1_ADDR, BIT_SET, timeout)) {
DEBUG_PUTS("Timeout while waiting for address bit set");
return ERROR_CODE;
}
// Clear ADDR bit
clearAddressFlag(h);
sendData(h, command);
// wait for tx buffer empty
if (!waitFlag((&h->SR1), I2C_SR1_TXE, BIT_SET, timeout)) {
DEBUG_PUTS("Timeout while waiting for buffer empty");
return ERROR_CODE;
}
uint8_t length = 3;
uint8_t tmpBuffer[length+1];
memset(tmpBuffer, 0x00, 4);
// Enable automatic ACK generation
enableAutomaticACK(h);
// Generate start bit
sendStartBit(h);
// Wait for start bit set
if (!waitFlag((&h->SR1), I2C_SR1_SB, BIT_SET, timeout)) {
DEBUG_PUTS("Timeout while waiting for repeted start bit set");
return ERROR_CODE;
}
// Send the read command to the slave address
sendAddress(h, deviceAddress, I2C_READ);
// Wait for address bit set
if (!waitFlag((&h->SR1), I2C_SR1_ADDR, BIT_SET, timeout)) {
DEBUG_PUTS("Timeout while waiting for address bit set");
return ERROR_CODE;
}
// Clear ADDR bit by reading status register
clearAddressFlag(h);
// Now we must read the data from the slave
if (length > 2) {
// Receive the first n-2 bytes
for (uint8_t i=0; i < length-2; i++) {
// Wait for Byte Transfer ready
if (!waitFlag((&h->SR1), I2C_SR1_BTF, BIT_RESET, timeout)) {
DEBUG_PUTS("Timeout while waiting for Byte Transfer ready");
return ERROR_CODE;
}
tmpBuffer[i] = h->DR;
// Wait for Byte Transfer Finished
if (!waitFlag((&h->SR1), I2C_SR1_BTF, BIT_SET, timeout)) {
DEBUG_PUTS("Timeout while waiting for Byte Transfer Finished");
return ERROR_CODE;
}
}
// Wait for Byte Transfer ready
if (!waitFlag((&h->SR1), I2C_SR1_BTF, BIT_RESET, timeout)) {
DEBUG_PUTS("Timeout while waiting for Byte Transfer ready");
return ERROR_CODE;
}
// Disable automatic ACK generation
disableAutomaticACK(h);
// Read the second last byte
tmpBuffer[length-1] = h->DR;
// Send stop bit
sendStopBit(h);
// Enable packet error check
h->CR1 |= I2C_CR1_PEC;
// Read the last byte
tmpBuffer[length] = h->DR;
temp = tmpBuffer[3]*256 + tmpBuffer[2];
uint8_t pec = h->SR2 &= I2C_SR2_PEC_Msk;
if ((h->SR1 & I2C_SR1_PECERR) != 0) {
puts("PEC ERROR");
}
}
return temp;
}
Found the bug. PECERR must be cleared by software. The first transmission after power on occasionally fails.
if ((h->SR1 & I2C_SR1_PECERR) != 0) {
DEBUG_PUTS("PEC ERROR");
h->SR1 &= ~I2C_SR1_PECERR;
return ERROR_CODE;
}
I've attached an image showing my oscilloscope readout which is from the code below. Context: I have a Pi and a PIC which need to communicate through UART connection. I've implemented my own flow control which can be seen in the image attached [RTS = Yellow Trace, CTS = Blue Trace, Rx = Green Trace]. The code runs through and is caught in the final switch case statement which turns on an LED. But when i debug the code, no values (well the only value which is read is zero) are read in. At first i thought that i'd configured my PIC clock wrong (which is used to derive the baud rate), but i don't think this is the case. Second i through the FIFO buffer was full of zeros only and considering that i'm sending only four packets of information to the PIC, and my FIFO is 4 registers deep that this was the reason why non of the information was appearing. So i executed a code which removes the dummy bytes but this did not work.
All that is received:
0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0> etc
I got the right settings selected: baud rate: 9600 data bits: 8 parity: none stop bits: 1
If anyone is willing to spend some time looking at my code, can you see any obvious errors?
https://i.stack.imgur.com/aQoAL.jpg
Minimum Reproducible Example
# include <xc.h>
# include <math.h>
# include <stdio.h>
# include <stdio.h>
//Configuration Bits
#pragma config FNOSC = FRCPLL // Internal Fast RC Oscillator (8MHz)
#pragma config FPLLIDIV = DIV_2 // Divide FRC before PLL (Now 4MHz)
#pragma config FPLLMUL = MUL_20 // PLL Multiply (Now 80MHz)
#pragma config FPLLODIV = DIV_2 // Divide After PLL (Now 40MHz)
#pragma config FPBDIV = DIV_1 // Pheripheral Bus Clock (At 40KHz)
#pragma config FWDTEN = OFF // Watchdog Timer Disabled
#pragma config ICESEL = ICS_PGx2 // ICE/ICD Comm Channel Select
#pragma config JTAGEN = OFF // Disable JTAG
#pragma config FSOSCEN = OFF // Disable Secondary Oscillator
//*****************************UART Functions***********************************
void UART_Config (void) // Baude Rate of 9600, 8-Bit Data , 1 Stop Bit
{
U1MODEbits.BRGH = 0;
U1BRG = 259; //U1BRG = (40M/ (16 * 9.6k))) - 1
U1MODEbits.SIDL = 0; // Continue operation in SLEEP mode
U1MODEbits.IREN = 0; // IrDA is disabled
U1MODEbits.RTSMD = 0; // U1RTS pin is in Flow Control mode
U1MODEbits.UEN = 0b00; // U1TX, U1RX are enabled
U1MODEbits.WAKE = 1; // Wake-up enabled
U1MODEbits.LPBACK = 0; // Loopback mode is disabled
U1MODEbits.RXINV = 0; // U1RX IDLE state is '1'
U1MODEbits.PDSEL = 0b00; // 8-bit data, no parity
U1MODEbits.STSEL = 0; // 1 stop bit
U1STAbits.UTXINV = 0; // U1TX IDLE state is '1'
U1MODEbits.ON = 1; // UART1 is enabled
U1STAbits.URXEN = 1; // UART1 receiver is enabled
U1STAbits.UTXEN = 1; // UART1 transmitter is enabled
}
void Send_UART_Data(unsigned int c) // PIC Sending Data for Pi to Read
{
U1STAbits.UTXEN = 1; // Make sure transmitter is enabled
// while(CTS) // Optional CTS (Clear to Send) use
while(U1STAbits.UTXBF); // Wait while buffer is full
U1TXREG = c; // Transmit character
}
int Read_UART_Data (void) // PIC Reading Sent Data from Pi
{
int c;
while(!U1STAbits.URXDA) // Wait for information to be received
c = (int)U1RXREG; // Convert Character to Value
return c;
}
ADC_To_UART (unsigned int ADC)
{
unsigned int temp_A = 0x00;
unsigned int temp_B = 0x00;
// Splitting a 10 Bit Word Into 2 Bytes [aa aaaa aabb]
// Start Bit = 1 , Stop Bit = 0
// UART Transmission Pattern [1 aaaa aaaa 0 0000 00 bb]
temp_A = ADC >> 2; // MSB(8 Bits) ~ ADC[9:2] [aaaa aaaa]
temp_B = ADC & 0x003; // LSB(2 Bits) ~ ADC[1:0] [0000 00bb]
Send_UART_Data(temp_A);
Send_UART_Data(temp_B);
}
[enter image description here][1]
//*********************Enumerated Variable Declaration**************************
//Program Flow Control
enum Comm_State {Phase1A, Phase1B, Phase1C, Phase1D, Phase1E, Phase2A, Phase2B, Phase2C, Phase2D, Phase2E, Phase2F, Phase2G};
//******************************************************************************
//********************************MAIN******************************************
int main( )
{
//***************************Configuration**********************************
// I/O Definitions
#define UART_TRIS_RX TRISBbits.TRISB13 // UART RX - Reciever Pin (PPS)
#define UART_TRIS_TX TRISBbits.TRISB15 // UART TX - Transmission Pin (PPS)
#define UART_TRIS_CTS_PIC TRISAbits.TRISA4 // UART CTS_1 - Clear to Send - Output [CTS PIC]
#define UART_TRIS_RTS_PIC TRISBbits.TRISB4 // UART RTS_1 - Ready to Send - Output [RTS PIC]
#define UART_TRIS_CTS_PI TRISAbits.TRISA3 // UART CTS_2 - Clear to Send - Input [CTS PI]
#define UART_TRIS_RTS_PI TRISAbits.TRISA2 // UART_RTS_2 - Ready to Send - Input [RTS PI]
#define SPI_TRIS_SCK TRISBbits.TRISB14 // SPI SCK - Serial Clock Pin (PPS?)
#define SPI_TRIS_SDO TRISBbits.TRISB6 // SPI SDO - Serial Data Out Pin (PPS?)
#define SPI_TRIS_CS_1 TRISBbits.TRISB8 // SPI CS1 - DAC 2 Chip Select Pin (PPS?)
#define SPI_TRIS_CS_2 TRISBbits.TRISB7 // SPI CS2 - DAC 1 Chip Select Pin (PPS?)
#define AN4_TRIS TRISBbits.TRISB2 // Analogue Read 3
#define AN3_TRIS TRISBbits.TRISB1 // Analogue Read 2
#define AN2_TRIS TRISBbits.TRISB0 // Analogue Read 1
#define V_REF_TRIS_Plus TRISAbits.TRISA0 // Analogue V_REF(+) (Forms VRange)
#define V_REF_TRIS_Minus TRISAbits.TRISA1 // Analogue V_REF(-) (Forms VRange)
#define Reg_Enable_TRIS_D TRISBbits.TRISB9 // Regulator Digital Control (Output)
#define Reg_Enable_TRIS_M TRISBbits.TRISB12 // Regulator Button (Input)
// Port Input/Output Configuration [TRISB]
TRISB = 0x1004; // All of PortB set as Outputs Except for RB12 (Reg Enable) and RB2 (Input -> Analogue Input (Voltage)) (Port B) = (0000 ... 0100)
TRISA = 0x0003; // Set up A0 [Pin 2] and A1 [Pin 3] as V_REF(+) and V_REF(-) Respectively (Port B) = (0000 ... 0011)
UART_TRIS_RX = 1; // UART Receiver ~ Input
UART_TRIS_TX = 0; // UART Transmission ~ Output
UART_TRIS_CTS_PIC = 0; // UART "CTS_PIC" ~ Output
UART_TRIS_RTS_PIC = 0; // UART "RTS_PIC" ~ Output
UART_TRIS_CTS_PI = 1; // UART "CTS_PI" ~ Input
UART_TRIS_RTS_PI = 1; // UART "RTS_PI" ~ Input
SPI_TRIS_SCK = 0; // SPI Clock ~ Output
SPI_TRIS_SDO = 0; // SPI Data Output ~ Output
SPI_TRIS_CS_1 = 0; // SPI Chip Select 1 ~ Output
SPI_TRIS_CS_2 = 0; // SPI Chip Select 2 ~ Output
AN4_TRIS = 1; // Analogue Read In ~ Input
AN3_TRIS = 1; // Analogue Read In ~ Input
AN2_TRIS = 1; // Analogue Read In ~ Input
V_REF_TRIS_Plus = 1; // V_Ref(+) ~ Input
V_REF_TRIS_Minus = 1; // V_Ref(-) Differential Measurements ~ Input
Reg_Enable_TRIS_D = 0; // Regulator Digital Control (Output)
Reg_Enable_TRIS_M = 1; // Regulator Switch Control (Input)
// Peripheral Pin Select Configurations
U1RXR = 0x0011; // UART PPS Mapping
RPB15R = 0x0001; // UART PPS Mapping
// Analogue Pin Configurations
ANSELB = 0x0028; // RB0 RB1 RB2 = AN2 AN3 AN4 [0001 1100]
ANSELA = 0x0000; // Set all Analogue Inputs of Port A Off
//**************Sub-System Configurations*********************************//
// UART Control Configure
UART_Config(); //UART Control Configure
#define PIC_CTS LATAbits.LATA4 // Output Set Definition [1]
#define PIC_RTS LATBbits.LATB4 // Output Set Definition [2]
#define PI_CTS PORTAbits.RA3 // Input Read Definition [2]
#define PI_RTS PORTAbits.RA2 // Input Read Definition [1]
// Analogue Control Configure
ADC_Config(); // Configure ADC
AD1CON1SET = 0x8000; // Enable ADC
//***************Variable Declarations************************************//
enum Comm_State Communication_State = Phase1A; //Controller Variable
unsigned int temp1 = 0;
unsigned int Comms_Flag_1 = 0;
unsigned int ConFlag = 1;
unsigned int i = 1;
unsigned int UART_ADC_CV_1 = 0;
unsigned int UART_ADC_CV_2 = 0;
unsigned int ADC_CV = 0;
unsigned int UART_ADC_CC_1 = 0;
unsigned int UART_ADC_CC_2 = 0;
unsigned int ADC_CC = 0;
unsigned int DAC_CV = 0;
float I_CC = 0;
float V_CV = 0;
//***************Program Flow - Switch State Controlled*******************//
while(1)
{
switch (Communication_State)
{
case Phase1A: // Check For Pi Ready to Send CV ADC Value
//PIC_CTS = 0;
//Pic_Refresh();
PIC_RTS = 0;
PIC_CTS = 1;
if (PI_RTS == 1)
{
PIC_CTS = 0;
Communication_State = Phase1B;
}
break;
case Phase1B: // Receive CV ~ 12 Bit ADC Value [Two Data Packets with 0.01 Second Delay]
ConFlag = 1;
i = 1;
while (ConFlag == 1)
{
if (PI_RTS == 1 && i == 1)
{
UART_ADC_CV_1 = Read_UART_Data(); //Data Packet 1 Returned - MSB(Bit 15) to Bit 8
i++;
}
else if (PI_RTS == 1 && i == 2)
{
UART_ADC_CV_2 = Read_UART_Data(); //Data Packet 2 Returned - Bit (7)) to LSB(Bit 0)
}
else
{
ConFlag = 0;
}
}
Communication_State = Phase1C;
break;
case Phase1C: // Check for CC Value
delay(); //Ensure that Pi_RTS has gone low after sending last Transmission (Prevents Code from Running Away)
PIC_CTS = 1;
if (PI_RTS == 1)
{
PIC_CTS = 0;
Communication_State = Phase1D;
}
break;
case Phase1D: // Receive CC Value [Two Data Packets with 0.01 Second Delay]
ConFlag = 1;
i = 1;
while (ConFlag == 1)
{
if (PI_RTS == 1 && i == 1)
{
UART_ADC_CC_1 = Read_UART_Data(); //Data Packet 1 Returned - MSB(Bit 15) to Bit 8
i++;
}
else if (PI_RTS == 1 && i == 2)
{
UART_ADC_CC_2 = Read_UART_Data(); //Data Packet 2 Returned - Bit (7)) to LSB(Bit 0)
}
else
{
ConFlag = 0;
}
}
Communication_State = Phase1E;
break;
case Phase1E: // Calculations
// CV Calculations
temp1 = UART_ADC_CV_1 << 8;
ADC_CV = temp1 + UART_ADC_CV_2;
V_CV = ADC_CV * (4.096/4096);
DAC_CV = ADC_CV | 4096;
Comms_Flag_1 = SPI_Transfer(DAC_CV ,1); // Data Transmitted to DAC 1, Upon Transmission LED Turns Green (No Acknowledgement)
// CC Calculations
temp1 = UART_ADC_CC_1 << 8;
ADC_CC = temp1 + UART_ADC_CC_2;
I_CC = ADC_CC * (4.096/4096);
Communication_State = Phase2A;
break;
case Phase2A:
while(1)
{
LATBbits.LATB5 = 1;
}
break;
}
}
return 1;
}
In Read_UART_Data, you have:
while(!U1STAbits.URXDA)
c = (int)U1RXREG;
I think you're missing a semicolon because this is actually:
while (!U1STAbits.URXDA)
c = (int) U1RXREG;
This means that c is set only when the UART receiver is not ready.
What I think you meant is:
while (!U1STAbits.URXDA);
c = (int) U1RXREG;
I'm able to receive with the following code, but unfortunately, nothing is sent back. What am I doing wrong?
#include <pic18f25k80.h>
#include "config.h"
#include <usart.h>
int i = 0;
unsigned char MessageBuffer[200];
void main() {
OSCCONbits.IRCF = 0b110; // 8MHz
TRISB6 = 0; // TX set as output
TRISB7 = 0; // RX set as output
// Clear TX interrupt
// Set RX interrupt
// 8-bit Asynch. mode
// BRGH = 1 = high baud mode
// 51 = ((8MHz/baud)/16)-1 with baud = 9600
Open2USART(USART_TX_INT_OFF & USART_RX_INT_ON & USART_ASYNCH_MODE
& USART_EIGHT_BIT & USART_BRGH_HIGH, 51 );
RC2IF = 0; // reset RX2 flag
RC2IP = 0; // not high priority
RC2IE = 1; // Eneble RX2 interrupt
INTCONbits.PEIE = 1; // enable peripheral interrupts
INTCONbits.GIE = 1; // enable interrupts
RCSTA2bits.SPEN = 1; // enable USART
while(1){
}
}
void interrupt ISR () {
if(PIR3bits.RC2IF == 1) {
if(i<200) { // buffer size
MessageBuffer[i] = Read2USART(); // read byte from RX reg
if (MessageBuffer[i] == 0x0D) { // check for return key
puts2USART(MessageBuffer);
for(;i>0;i--)
MessageBuffer[i] = 0x00; // clear array
i=0;
return;
}
i++;
RC2IF = 0; // clear RX flag
} else {
puts2USART(MessageBuffer);
for(;i>0;i--)
MessageBuffer[i] = 0x00; // clear array
i = 0;
return;
}
}
}
I'm transmitting the 0x41 hex code, I checked with the scope and see that is is being received. And according to the code I have, an echo of the received data should be sent back. When I check the TX pin, nothing is happening.
Add USART_CONT_RX to Open2USART to enable continuous receive.
Also, it's a good idea to do the minimum necessary in the interrupt service routine. Consider something like:
void interrupt ISR () {
char data;
if(PIR3bits.RC2IF == 1) {
data = Read2USART(); // always read byte from RX reg (clears RC2IF)
if(i<200) { // buffer size
MessageBuffer[i] = data; // read byte from RX reg
i++;
}
else{
// flag buffer full error
}
}
}
and doing the rest of what you are doing in the while(1) loop.
How can I send the string "MY STRING" from a master pic to a slave?
I'm using MicroC RS-485 library example:
http://www.mikroe.com/download/eng/documents/compilers/mikroc/pro/pic/help/rs-485_library.htm
Im trying to send string from master to slave: and seting dat[7] = "my string"; expecting dat[7] on slave with my string but im geting empty value...
Original code in the link bottom.
Master
char dat[10]; // buffer for receving/sending messages
char i,j;
sbit rs485_rxtx_pin at RC2_bit; // set transcieve pin
sbit rs485_rxtx_pin_direction at TRISC2_bit; // set transcieve pin direction
// Interrupt routine
void interrupt() {
RS485Master_Receive(dat);
}
void main(){
long cnt = 0;
ANSEL = 0; // Configure AN pins as digital I/O
ANSELH = 0;
C1ON_bit = 0; // Disable comparators
C2ON_bit = 0;
PORTB = 0;
PORTD = 0;
TRISB = 0;
TRISD = 0;
UART1_Init(9600); // initialize UART1 module
Delay_ms(100);
RS485Master_Init(); // initialize MCU as Master
dat[0] = 0xAA;
dat[1] = 0xF0;
dat[2] = 0x0F;
dat[4] = 0; // ensure that message received flag is 0
dat[5] = 0; // ensure that error flag is 0
dat[6] = 0;
dat[7] = "MY STRING";
RS485Master_Send(dat,1,160);
RCIE_bit = 1; // enable interrupt on UART1 receive
TXIE_bit = 0; // disable interrupt on UART1 transmit
PEIE_bit = 1; // enable peripheral interrupts
GIE_bit = 1; // enable all interrupts
while (1){
// upon completed valid message receiving
// data[4] is set to 255
cnt++;
if (dat[5]) { // if an error detected, signal it
PORTD = 0xAA; // by setting portd to 0xAA
}
if (dat[4]) { // if message received successfully
cnt = 0;
dat[4] = 0; // clear message received flag
j = dat[3];
for (i = 1; i <= dat[3]; i++) { // show data on PORTB
PORTB = dat[i-1];
} // increment received dat[0]
dat[0] = dat[0]+1; // send back to master
Delay_ms(1);
RS485Master_Send(dat,1,160);
}
if (cnt > 100000) {
PORTD ++;
cnt = 0;
RS485Master_Send(dat,1,160);
if (PORTD > 10) // if sending failed 10 times
RS485Master_Send(dat,1,50); // send message on broadcast address
}
}
}
Slave:
char dat[9]; // buffer for receving/sending messages
char i,j;
sbit rs485_rxtx_pin at RC2_bit; // set transcieve pin
sbit rs485_rxtx_pin_direction at TRISC2_bit; // set transcieve pin direction
// Interrupt routine
void interrupt() {
RS485Slave_Receive(dat);
}
void main() {
ANSEL = 0; // Configure AN pins as digital I/O
ANSELH = 0;
C1ON_bit = 0; // Disable comparators
C2ON_bit = 0;
PORTB = 0;
PORTD = 0;
TRISB = 0;
TRISD = 0;
PORTA = 0;
TRISA = 0;
UART1_Init(9600); // initialize UART1 module
Delay_ms(100);
RS485Slave_Init(160); // Intialize MCU as slave, address 160
dat[4] = 0; // ensure that message received flag is 0
dat[5] = 0; // ensure that message received flag is 0
dat[6] = 0; // ensure that error flag is 0
RCIE_bit = 1; // enable interrupt on UART1 receive
TXIE_bit = 0; // disable interrupt on UART1 transmit
PEIE_bit = 1; // enable peripheral interrupts
GIE_bit = 1; // enable all interrupts
while (1) {
if(dat[7]=="MY STRING"){
RCA0_bit = 1;
}
if (dat[5]) { // if an error detected, signal it by
PORTD = 0xAA; // setting portd to 0xAA
dat[5] = 0;
}
if (dat[4]) { // upon completed valid message receive
dat[4] = 0; // data[4] is set to 0xFF
j = dat[3];
for (i = 1; i <= dat[3];i++){
PORTB = dat[i-1];
}
dat[0] = dat[0]+1; // increment received dat[0]
Delay_ms(1);
RS485Slave_Send(dat,1); // and send it back to master
}
}
}
char dat[9]; defines an array of 9 bytes, so dat[7] = "MY STRING"; will only store a truncated address not the actual string. memcpy can be used to copy strings from one buffer to another.
see: http://www.cplusplus.com/reference/cstring/memcpy/
dat[7]=="MY STRING" will not work as your comparing the 2 byte address of the string literal "MY STRING" with the single byte stored at dat[7]. If you need to compare strings for differences, strcmp works.
see: http://www.cplusplus.com/reference/cstring/strcmp/
PIC: PIC32MX564F128L
EEPROM: 24AA16
I've put together some code for the PIC, in C, to read & write to an external EEPROM, via I2C.
When I use these methods to write a single byte, then read it back again for verification, it works.
If I change the write location, it works, so I presume the addressing is working, and the byte I read back matches the write, so that appears to work too.
All good so far!
I then extended the code to use the same routine 100 times, writing different bytes in adjacent locations. I.E. Write values 0 to 99 in Locations x to x + 99.
I then proceeded to read back the 100 locations to verify the writes, and this is where it goes wrong.
It would appear, from various tests, that the write method performs all the writes in the same location, as the read method gets the last value (99) from the first location, and nothing (0xFF) from the other locations!
The scope shows that the clock is good, and the data line toggling, which I expected as the single write works.
Debug on the PIC shows that the addresses being used by the methods are sequential, so I'm a little stumped as to why all the writes are being performed in the same location! I can change this location, but it always just uses the first byte for all values.
Anyone know what could be wrong?
My code is here, and the entry point is testEeprom():
// ----------------------------------------------------------------------------
#include "eeprom.h"
//#define _PLIB_DISABLE_LEGACY
#include <plib.h>
//// ----------------------------------------------------------------------------
#define SYS_CLOCK (80000000L)
#define GetSystemClock() (SYS_CLOCK)
#define GetPeripheralClock() (SYS_CLOCK / 2)
#define GetInstructionClock() (SYS_CLOCK)
#define I2C_CLOCK_FREQ 100000
#define EEPROM_I2C_BUS I2C1
#define EEPROM_ADDRESS 0x50 // 0b1010000 Serial EEPROM address
#define EEPROM_STORAGE_LOCATION 0x0100
#define DATA_ARRAY_SIZE 100
// ----------------------------------------------------------------------------
UINT8 EEPROM_Data_Array[DATA_ARRAY_SIZE];
UINT8 EEPROM_Data_Array_RX[DATA_ARRAY_SIZE];
BOOL EEPROM_Success;
I2C_7_BIT_ADDRESS SlaveAddress;
// ----------------------------------------------------------------------------
void i2c_wait(unsigned int cnt)
{
while (--cnt)
{
Nop();
Nop();
} // while
}
// ----------------------------------------------------------------------------
BOOL StartTransfer(BOOL restart)
{
I2C_STATUS status;
// Send the Start (or Restart) signal
if (restart)
{
I2CRepeatStart(EEPROM_I2C_BUS);
}
else
{
// Wait for the bus to be idle, then start the transfer
while (!I2CBusIsIdle(EEPROM_I2C_BUS));
if (I2CStart(EEPROM_I2C_BUS) != I2C_SUCCESS)
{
debugTrace("I2C Error: Bus collision during transfer Start\r\n");
return FALSE;
}
}
// Wait for the signal to complete
do
{
status = I2CGetStatus(EEPROM_I2C_BUS);
}
while (!(status & I2C_START));
return TRUE;
}
// ----------------------------------------------------------------------------
BOOL TransmitOneByte(UINT8 data)
{
// Wait for the transmitter to be ready
while (!I2CTransmitterIsReady(EEPROM_I2C_BUS));
// Transmit the byte
if (I2CSendByte(EEPROM_I2C_BUS, data) == I2C_MASTER_BUS_COLLISION)
{
debugTrace("I2C Error: I2C Master Bus Collision\r\n");
return FALSE;
}
// Wait for the transmission to finish
while (!I2CTransmissionHasCompleted(EEPROM_I2C_BUS));
return TRUE;
}
// ----------------------------------------------------------------------------
void StopTransfer(void)
{
I2C_STATUS status;
// Send the Stop signal
I2CStop(EEPROM_I2C_BUS);
// Wait for the signal to complete
do
{
status = I2CGetStatus(EEPROM_I2C_BUS);
}
while (!(status & I2C_STOP));
}
// ----------------------------------------------------------------------------
void initIcd()
{
UINT32 actualClock;
EEPROM_Success = TRUE;
// Set the I2C baudrate
actualClock = I2CSetFrequency(EEPROM_I2C_BUS, GetPeripheralClock(), I2C_CLOCK_FREQ);
if (abs(actualClock - I2C_CLOCK_FREQ) > I2C_CLOCK_FREQ / 10)
{
debugTrace("Error: I2C1 clock frequency (%u) error exceeds 10%%.\r\n", (unsigned) actualClock);
}
// Enable the I2C bus
I2CEnable(EEPROM_I2C_BUS, TRUE);
}
// ----------------------------------------------------------------------------
// Send the data to EEPROM to program one location
// ----------------------------------------------------------------------------
void txIcd(unsigned int address, unsigned char value)
{
BOOL Acknowledged;
int Index;
UINT8 i2cData[4];
int DataSz;
EEPROM_Success = TRUE;
// Initialize the data buffer
I2C_FORMAT_7_BIT_ADDRESS(SlaveAddress, EEPROM_ADDRESS, I2C_WRITE);
i2cData[0] = SlaveAddress.byte;
i2cData[1] = address >> 8; // EEPROM location to program (high address byte)
i2cData[2] = address & 0xFF; // EEPROM location to program (low address byte)
i2cData[3] = value; // EEPROM location to program (low address byte)
DataSz = 4;
// Start the transfer to write data to the EEPROM
if (!StartTransfer(FALSE))
{
debugTrace("I2C Error: Can't Start Transfer TX (1)\r\n");
return;
}
// Transmit all header
Index = 0;
while (EEPROM_Success && (Index < DataSz))
{
// Transmit a byte
if (TransmitOneByte(i2cData[Index]))
{
// Advance to the next byte
Index++;
// Verify that the byte was acknowledged
if (!I2CByteWasAcknowledged(EEPROM_I2C_BUS))
{
debugTrace("I2C Error: Sent byte was not acknowledged (1)\r\n");
EEPROM_Success = FALSE;
}
}
else
{
EEPROM_Success = FALSE;
}
}
// End the transfer (hang here if an error occured)
StopTransfer();
if (!EEPROM_Success)
{
debugTrace("I2C Error: No Success on TX (1)\r\n");
return;
}
// Wait for EEPROM to complete write process, by polling the ack status.
Acknowledged = FALSE;
do
{
// Start the transfer to address the EEPROM
if (!StartTransfer(FALSE))
{
debugTrace("I2C Error: Can't Start Transfer TX (2)\r\n");
return;
}
// Transmit just the EEPROM's address
if (TransmitOneByte(SlaveAddress.byte))
{
// Check to see if the byte was acknowledged
Acknowledged = I2CByteWasAcknowledged(EEPROM_I2C_BUS);
}
else
{
EEPROM_Success = FALSE;
}
// End the transfer (stop here if an error occured)
StopTransfer();
if (!EEPROM_Success)
{
debugTrace("I2C Error: No Success on TX (2)\r\n");
return;
}
}
while (Acknowledged != TRUE);
}
// ----------------------------------------------------------------------------
// Read the data back from the EEPROM.
// ----------------------------------------------------------------------------
unsigned char rxIcd(unsigned int address)
{
UINT8 i2cbyte;
UINT8 i2cData[3];
int DataSz;
int Index;
EEPROM_Success = TRUE;
// Initialize the data buffer
I2C_FORMAT_7_BIT_ADDRESS(SlaveAddress, EEPROM_ADDRESS, I2C_WRITE);
i2cData[0] = SlaveAddress.byte;
i2cData[1] = address >> 8; // EEPROM location to program (high address byte)
i2cData[2] = address & 0xFF; // EEPROM location to program (low address byte)
DataSz = 3;
// Start the transfer to write data to the EEPROM
if (!StartTransfer(FALSE))
{
debugTrace("I2C Error: Can't Start Transfer TX (1)\r\n");
return;
}
// Transmit all header
Index = 0;
while (EEPROM_Success && (Index < DataSz))
{
// Transmit a byte
if (TransmitOneByte(i2cData[Index]))
{
// Advance to the next byte
Index++;
}
else
{
EEPROM_Success = FALSE;
}
// Verify that the byte was acknowledged
if (!I2CByteWasAcknowledged(EEPROM_I2C_BUS))
{
debugTrace("I2C Error: Sent byte was not acknowledged (1)\r\n");
EEPROM_Success = FALSE;
}
}
// Restart and send the EEPROM's internal address to switch to a read transfer
if (EEPROM_Success)
{
// Send a Repeated Started condition
if (!StartTransfer(TRUE))
{
debugTrace("I2C Error: Can't Start Transfer TX (4)\r\n");
return;
}
// Transmit the address with the READ bit set
I2C_FORMAT_7_BIT_ADDRESS(SlaveAddress, EEPROM_ADDRESS, I2C_READ);
if (TransmitOneByte(SlaveAddress.byte))
{
// Verify that the byte was acknowledged
if (!I2CByteWasAcknowledged(EEPROM_I2C_BUS))
{
debugTrace("I2C Error: Sent byte was not acknowledged (3)\r\n");
EEPROM_Success = FALSE;
}
}
else
{
EEPROM_Success = FALSE;
}
}
// Read the data from the desired address
if (EEPROM_Success)
{
if (I2CReceiverEnable(EEPROM_I2C_BUS, TRUE) == I2C_RECEIVE_OVERFLOW)
{
debugTrace("I2C Error: I2C Receive Overflow\r\n");
EEPROM_Success = FALSE;
}
else
{
while (!I2CReceivedDataIsAvailable(EEPROM_I2C_BUS));
i2cbyte = I2CGetByte(EEPROM_I2C_BUS);
}
}
// End the transfer (stop here if an error occured)
StopTransfer();
if (!EEPROM_Success)
{
debugTrace("I2C Error: No Success on TX (3)\r\n");
return;
}
return i2cbyte;
}
// ----------------------------------------------------------------------------
void testEeprom(void)
{
unsigned int i;
BOOL failed = FALSE;
unsigned char value;
// Create & Write 100 byte array
for (i = 0; i < DATA_ARRAY_SIZE; i++)
{
EEPROM_Data_Array[i] = i;
initIcd();
txIcd(EEPROM_STORAGE_LOCATION + i, EEPROM_Data_Array[i]);
StopTransfer();
I2CEnable(EEPROM_I2C_BUS, FALSE);
} // for i
// Read back & varify data against array
for (i = 0; i < DATA_ARRAY_SIZE; i++)
{
initIcd();
value = rxIcd(EEPROM_STORAGE_LOCATION + i);
if (EEPROM_Data_Array[i] != value)
{
failed = TRUE;
break;
}
StopTransfer();
I2CEnable(EEPROM_I2C_BUS, FALSE);
} // for i
if (failed == FALSE)
{
debugTrace("I2C SUCCESS\r\n");
}
else
{
debugTrace("I2C FAILED %d: %d != %d\r\n", i, value, EEPROM_Data_Array[i]);
}
while(1);
}
// ----------------------------------------------------------------------------