SPI implementation stuck on “while(!spi_is_tx_empty(WINC1500_SPI));” - avr

I'm currently implementing a driver for the WINC1500 to be used with an ATMEGA32 MCU and it's getting stuck on this line of "while(!spi_is_tx_empty(WINC1500_SPI));". The code builds and runs but it won't clear what's inside in this function to proceed through my code and boot up the Wifi Module. I've been stuck on this problem for weeks now with no progress and don't know how to clear it.
static inline bool spi_is_tx_empty(volatile avr32_spi_t *spi)
{
// 1 = All Transmissions complete
// 0 = Transmissions not complete
return (spi->sr & AVR32_SPI_SR_TXEMPTY_MASK) != 0;
}
Here is my implementation of the SPI Tx/Rx function
void m2mStub_SpiTxRx(uint8_t *p_txBuf,
uint16_t txLen,
uint8_t *p_rxBuf,
uint16_t rxLen)
{
uint16_t byteCount;
uint16_t i;
uint16_t data;
// Calculate the number of clock cycles necessary, this implies a full-duplex SPI.
byteCount = (txLen >= rxLen) ? txLen : rxLen;
// Read / Transmit.
for (i = 0; i < byteCount; ++i)
{
// Wait for transmitter to be ready.
while(!spi_is_tx_ready(WINC1500_SPI));
// Transmit.
if (txLen > 0)
{
// Send data from the transmit buffer
spi_put(WINC1500_SPI, *p_txBuf++);
--txLen;
}
else
{
// No more Tx data to send, just send something to keep clock active.
// Here we clock out a don't care byte
spi_put(WINC1500_SPI, 0x00U);
// Not reading it back, not being cleared 16/1/2020
}
// Reference http://asf.atmel.com/docs/latest/avr32.components.memory.sdmmc.spi.example.evk1101/html/avr32_drivers_spi_quick_start.html
// Wait for transfer to finish, stuck on here
// Need to clear the buffer for it to be able to continue
while(!spi_is_tx_empty(WINC1500_SPI));
// Wait for transmitter to be ready again
while(!spi_is_tx_ready(WINC1500_SPI));
// Send dummy data to slave, so we can read something from it.
spi_put(WINC1500_SPI, 0x00U); // Change dummy data from 00U to 0xFF idea
// Wait for a complete transmission
while(!spi_is_tx_empty(WINC1500_SPI));
// Read or throw away data from the slave as required.
if (rxLen > 0)
{
*p_rxBuf++ = spi_get(WINC1500_SPI);
--rxLen;
}
else
{
spi_get(WINC1500_SPI);
}
}
Debug output log
Disable SPI
Init SPI module as master
Configure SPI and Clock settings
spi_enable(WINC1500_SPI)
InitStateMachine()
INIT_START_STATE
InitStateMachine()
INIT_WAIT_FOR_CHIP_RESET_STATE
m2mStub_PinSet_CE
m2mStub_PinSet_RESET
m2mStub_GetOneMsTimer();
SetChipHardwareResetState (CHIP_HARDWARE_RESET_FIRST_DELAY_1MS)
InitStateMachine()
INIT_WAIT_FOR_CHIP_RESET_STATE
if(m2m_get_elapsed_time(startTime) >= 2)
m2mStub_PinSet_CE(M2M_WIFI_PIN_HIGH)
startTime = m2mStub_GetOneMsTimer();
SetChipHardwareResetState(CHIP_HARDWARE_RESET_SECOND_DELAY_5_MS);
InitStateMachine()
INIT_WAIT_FOR_CHIP_RESET_STATE
m2m_get_elapsed_time(startTime) >= 6
m2mStub_PinSet_RESET(M2M_WIFI_PIN_HIGH)
startTime = m2mStub_GetOneMsTimer();
SetChipHardwareResetState(CHIP_HARDWARE_RESET_FINAL_DELAY);
InitStateMachine()
INIT_WAIT_FOR_CHIP_RESET_STATE
m2m_get_elapsed_time(startTime) >= 10
SetChipHardwareResetState(CHIP_HARDWARE_RESET_COMPLETE)
retVal = true // State machine has completed successfully
g_scanInProgress = false
nm_spi_init();
reg = spi_read_reg(NMI_SPI_PROTOCOL_CONFIG)
Wait for a complete transmission
Wait for transmitter to be ready
SPI_PUT(WINC1500_SPI, *p_txBuf++);
--txLen;
Wait for transfer to finish, stuck on here
Wait for transfer to finish, stuck on here

The ATmega32 is an 8-bit AVR but you seem to be using code for the AVR32, a family of 32-bit AVRs. You're probably just using the totally wrong code and you should consult the datasheet of the ATmega32, and search for SPI for the AVR ATmega family.

Related

UART program for PIC18f65k40

I'm trying to program my MCU in mickroc still I do not get a output.
Is there any difference between PIC18f65k40 and PIC18f65k22 in terms of initiating uart transmission? Whether there is any need to initiate or disable any special registers in PIC18f65k40?
In mikroc software there present a library for uart so I just copied the program from mickroe website and add my transmitter and receiver pins(RX4PPS = 0x11; and TX4PPS = 0x10;)in program by configuring portc as output but my circuit does not work.
char i ;
void main()
{
TRISC = 0b00000000;// making port as output
RX4PPS = 0x11;
TX4PPS = 0x10;
UART4_Init(9600); // Initialize USART module
// (8 bit, 9600 baud rate, no parity bit...)
delay_ms(500);
UART4_Write_Text("Hello world!");
UART4_Write(13); // Start a new line
UART4_Write(10);
UART4_Write_Text("PIC18F65K40 UART example");
UART4_Write(13); // Start a new line
UART4_Write(10);
while (1) {
if (UART4_Data_Ready()) { // If data has been received
i = UART4_Read(); // read it
UART4_Write(i); // and send it back
}
}
}
The PIC18F65k22 has only 2 UARTs and you are working with UART4. I guess the library don't support the controller. Better write the code on your own. There are some examples in the datasheet.

I²C Master Write with PIC18F45K50 : keeps SCL low

I'm writing my own I²C Master Write function according to Microchip's datasheet. I'm using MPLAB X. I generated the configuration with the Code Configurator, but here are the interesting bits :
// R_nW write_noTX; P stopbit_notdetected; S startbit_notdetected; BF RCinprocess_TXcomplete; SMP Standard Speed; UA dontupdate; CKE disabled; D_nA lastbyte_address;
SSP1STAT = 0x80;
// SSPEN enabled; WCOL no_collision; CKP Idle:Low, Active:High; SSPM FOSC/4_SSPxADD_I2C; SSPOV no_overflow;
SSP1CON1 = 0x28;
// SBCDE disabled; BOEN disabled; SCIE disabled; PCIE disabled; DHEN disabled; SDAHT 100ns; AHEN disabled;
SSP1CON3 = 0x00;
// Baud Rate Generator Value: SSP1ADD 80;
SSP1ADD = 0x50;
// clear the master interrupt flag
PIR1bits.SSP1IF = 0;
// enable the master interrupt
PIE1bits.SSP1IE = 1;
So : Standard Speed, 100ns hold time, Master Mode, clokck frequency about 50kHz.
I tried to follow the procedure described p238 of the datasheet :
http://ww1.microchip.com/downloads/en/DeviceDoc/30000684B.pdf
Here's my code :
#include "mcc_generated_files/mcc.h"
#include <stdio.h>
#define _XTAL_FREQ 16000000
#define RTS_PIN PORTDbits.RD3
#define CTS_PIN PORTDbits.RD2
#define LED_PIN PORTAbits.RA1
#define RX_FLAG PORTAbits.RA2
uint8_t c;
// Define putch() for printf())
void putch(char c)
{
EUSART1_Write(c);
}
void main(void)
{
// Initialize the device
SYSTEM_Initialize();
while (1)
{
// Generate a START condition by setting Start Enable bit
SSP1CON2bits.SEN = 1;
// Wait for START to be completed
while(!PIR1bits.SSPIF);
// Clear flag
PIR1bits.SSPIF = 0;
// Load the address + RW byte in SSP1BUF
// Address = 85 ; request type = WRITE (0)
SSP1BUF = 0b10101010;
// Wait for ack
while (SSP1CON2bits.ACKSTAT);
// Wait for MSSP interrupt
while (!PIR1bits.SSPIF);
// Load data (0x11) in SSP1BUF
SSP1BUF = 0x11;
// Wait for ack
while (SSP1CON2bits.ACKSTAT);
// Generate a STOP condition
SSP1CON2bits.PEN = 1;
// Wait for STOP to be completed
while(!PIR1bits.SSPIF);
// Clear flag
PIR1bits.SSPIF = 0;
// Wait for 1s before sending the next byte
__delay_ms(1000);
}
}
The slave device is an Arduino which I have tested with another Arduino (Master) to make sure it's working correctly.
My problem is : analysing the SDA/SCL signals with a logic analyser, when I start the PIC I get 2 correct messages, that's with correct address send and byte transmission, but at the end of the second SCL is held LOW, which makes all other writings bad (can't have a proper START condition if SCL is held LOW). BTW, at the end of the first transmission, SCL is held LOW for like 3ms, but then comes HIGH again without any reason.
Can anyone here point what I'm doing wrong ? Did I forget something ?
Thanx in advance.
Best regards.
Eric
PS : when testing the slave with another Arduino as the Master, SCL is set HIGH as soon as the transmission is over.
One thing I'm noticing is that after sending the slave address you are waiting for the ACK (ACKSTAT) then waiting for the SSPIF Interrupt Flag, but you are not checking for SSPIF after the data byte. You are only checking ACKSTAT. Maybe try waiting for and clearing the SSPIF before setting PEN to assert the stop conditon?
Have you checked the state of the SSPCON and SSPSTAT registers when this behavior occurs, that might help narrow down where the problem lies.
Thanx a lot for your answer !
I cleared SSP1IF after loading the data byte, and now it's working fine !
I think I understand now what was happening : the datasheet indicates that ACKSTAT is the only register bit that reacts on the rising edge of SCL, instead of the falling edge for the other bits. So in my code, I generate the STOP condition too early, and that might make it inoperative. Thus no STOP condition is generated, SCL is stuck LOW, and the next transmission cannot be started.
Furthermore, when I wait for the STOP condition to be completed, the SSP1IF flag is still set, so he doesn't actually wait and jumps directly to the delay() function. I don't know if that matters as he waits anyway, but it could matter if ever I tried to send packets one after the other.
So I here's the function I wrote, and which is working :
(BTW it can take up to 255 data bytes)
void MasterWrite(char _size, char* _data)
{
// Generate a START condition by setting Start Enable bit
SSP1CON2bits.SEN = 1;
// Wait for START to be completed
while(!PIR1bits.SSPIF);
// Clear flag
PIR1bits.SSPIF = 0;
// Load the address + RW byte in SSP1BUF
// Address = 85 ; request type = WRITE (0)
SSP1BUF = 0b10101010;
// Wait for ack
while (SSP1CON2bits.ACKSTAT);
// Wait for MSSP interrupt
while (!PIR1bits.SSPIF);
// Clear flag
PIR1bits.SSPIF = 0;
for (int i=0; i<_size; i++)
{
// Load data in SSP1BUF
SSP1BUF = *(_data+i);
// Wait for ack
while (SSP1CON2bits.ACKSTAT);
// Wait for MSSP interrupt
while (!PIR1bits.SSPIF);
// Clear flag
PIR1bits.SSPIF = 0;
}
// Generate a STOP condition
SSP1CON2bits.PEN = 1;
// Wait for STOP to be completed
while(!PIR1bits.SSPIF);
// Clear flag
PIR1bits.SSPIF = 0;
}
Thanx a lot again for your help !
Best regards.
Eric

Why is this DMA I2C transfer locking up execution?

I'm trying to change a library for STM32F407 to include DMA transfers when using I2C. I'm using it do drive an OLED screen. In its original form it is working w/o problems. In the comments, somebody added DMA, but also ported it to STM32F10 and I'm trying to port it back to F407.
My problem is, after enabling DMA transfer, debugger stops working (at exactly that line) - debugger activity LED stops / turns off and debugger stays at next statement.
After some more testing (blinking a led at certain events to see if they happen) I found out that code actually continues to a certain point (specifically, next time when DMA transfer is needed - in second call to update screen). After that, program doesn't continue (LED doesn't turn ON if set ON after that statement).
The weird thing is, I know the transfer is working because the screen gets a few characters written on it. That only happens if I don't debug step by step because CPU writes new data to screen buffer in the mean time and changes content of it before it is entirely sent to the screen by DMA (I will figure out how to fix that later - probably dual buffer, but it shouldn't interfere with DMA transfer anyway). However if I debug step by step, DMA finishes before CPU writes new content to screen buffer and screen is black (as it should be as buffer is first cleared). For testing, I removed the first call to DMA (after the clearing of buffer) and let the program write the text intended into buffer. It displays without any anomalies, so that means DMA must have finished, but something happened after. I simply can't explain why debugger stops working if DMA finishes the transfer.
I tried blinking a led in transfer finished interrupt handler of DMA but it never blinks, that means it is never fired. I would appreciate any help as I'm at a loss (been debugging for a few days now).
Thank you!
Here is relevant part of code (I have omitted rest of the code because there is a lot of it, but if required I can post). The code works without DMA (with ordinary I2C transfers), it only breaks with DMA.
// TM_STM32F4_I2C.h
typedef struct DMA_Data
{
DMA_Stream_TypeDef* DMAy_Streamx;
uint32_t feif;
uint32_t dmeif;
uint32_t teif;
uint32_t htif;
uint32_t tcif;
} DMA_Data;
//...
// TM_STM32F4_I2C.c
void TM_I2C_Init(I2C_TypeDef* I2Cx, uint32_t clockSpeed) {
I2C_InitTypeDef I2C_InitStruct;
/* Enable clock */
RCC->APB1ENR |= RCC_APB1ENR_I2C3EN;
/* Enable pins */
TM_GPIO_InitAlternate(GPIOA, GPIO_PIN_8, TM_GPIO_OType_OD, TM_GPIO_PuPd_UP, TM_GPIO_Speed_Medium, GPIO_AF_I2C3);
TM_GPIO_InitAlternate(GPIOC, GPIO_PIN_9, TM_GPIO_OType_OD, TM_GPIO_PuPd_UP, TM_GPIO_Speed_Medium, GPIO_AF_I2C3);
/* Check clock, set the lowest clock your devices support on the same I2C bus */
if (clockSpeed < TM_I2C_INT_Clocks[2]) {
TM_I2C_INT_Clocks[2] = clockSpeed;
}
/* Set values */
I2C_InitStruct.I2C_ClockSpeed = TM_I2C_INT_Clocks[2];
I2C_InitStruct.I2C_AcknowledgedAddress = TM_I2C3_ACKNOWLEDGED_ADDRESS;
I2C_InitStruct.I2C_Mode = TM_I2C3_MODE;
I2C_InitStruct.I2C_OwnAddress1 = TM_I2C3_OWN_ADDRESS;
I2C_InitStruct.I2C_Ack = TM_I2C3_ACK;
I2C_InitStruct.I2C_DutyCycle = TM_I2C3_DUTY_CYCLE;
/* Disable I2C first */
I2Cx->CR1 &= ~I2C_CR1_PE;
/* Initialize I2C */
I2C_Init(I2Cx, &I2C_InitStruct);
/* Enable I2C */
I2Cx->CR1 |= I2C_CR1_PE;
}
int16_t TM_I2C_WriteMultiDMA(DMA_Data* dmaData, I2C_TypeDef* I2Cx, uint8_t address, uint8_t reg, uint16_t len)
{
int16_t ok = 0;
// If DMA is already enabled, wait for it to complete first.
// Interrupt will disable this after transmission is complete.
TM_I2C_Timeout = 10000000;
// TODO: Is this I2C check ok?
while (I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY) && !I2C_GetFlagStatus(I2Cx, I2C_FLAG_TXE) && DMA_GetCmdStatus(dmaData->DMAy_Streamx) && TM_I2C_Timeout)
{
if (--TM_I2C_Timeout == 0)
{
return -1;
}
}
//Set amount of bytes to transfer
DMA_Cmd(dmaData->DMAy_Streamx, DISABLE); //should already be disabled at this point
DMA_SetCurrDataCounter(dmaData->DMAy_Streamx, len);
DMA_ClearFlag(dmaData->DMAy_Streamx, dmaData->feif | dmaData->dmeif | dmaData->teif | dmaData->htif | dmaData->tcif); // Clear dma flags
DMA_Cmd(dmaData->DMAy_Streamx, ENABLE); // enable DMA
//Send I2C start
ok = TM_I2C_Start(I2Cx, address, I2C_TRANSMITTER_MODE, I2C_ACK_DISABLE);
//Send register to write to
TM_I2C_WriteData(I2Cx, reg);
//Start DMA transmission, interrupt will handle transmit complete.
I2C_DMACmd(I2Cx, ENABLE);
return ok;
}
//...
// TM_STM32F4_SSD1306.h
#define SSD1306_I2C I2C3
#define SSD1306_I2Cx 3
#define SSD1306_DMA_STREAM DMA1_Stream4
#define SSD1306_DMA_FEIF DMA_FLAG_FEIF4
#define SSD1306_DMA_DMEIF DMA_FLAG_DMEIF4
#define SSD1306_DMA_TEIF DMA_FLAG_TEIF4
#define SSD1306_DMA_HTIF DMA_FLAG_HTIF4
#define SSD1306_DMA_TCIF DMA_FLAG_TCIF4
static DMA_Data ssd1306_dma_data = { SSD1306_DMA_STREAM, SSD1306_DMA_FEIF, SSD1306_DMA_DMEIF, SSD1306_DMA_TEIF, SSD1306_DMA_HTIF, SSD1306_DMA_TCIF };
#define SSD1306_I2C_ADDR 0x78
//...
// TM_STM32F4_SSD1306.c
void TM_SSD1306_initDMA(void)
{
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
DMA_DeInit(DMA1_Stream4);
DMA_Cmd(DMA1_Stream4, DISABLE);
//Configure DMA controller channel 3, I2C TX channel.
DMA_StructInit(&DMA_InitStructure); // Load defaults
DMA_InitStructure.DMA_Channel = DMA_Channel_3;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(I2C3->DR)); // I2C3 data register address
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)SSD1306_Buffer; // Display buffer address
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; // DMA from mem to periph
DMA_InitStructure.DMA_BufferSize = 1024; // Is set later in transmit function
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // Do not increment peripheral address
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // Do increment memory address
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; // DMA one shot, no circular.
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; // Tweak if interfering with other dma actions
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA1_Stream4, &DMA_InitStructure);
DMA_ITConfig(DMA1_Stream4, DMA_IT_TC, ENABLE); // Enable transmit complete interrupt
DMA_ClearITPendingBit(DMA1_Stream4, DMA_IT_TC);
// Set interrupt controller for DMA
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream4_IRQn; // I2C3 TX connect to stream 4 of DMA1
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x05;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x05;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// Set interrupt controller for I2C
NVIC_InitStructure.NVIC_IRQChannel = I2C3_EV_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
I2C_ITConfig(I2C3, I2C_IT_BTF, ENABLE);
}
extern void DMA1_Channel3_IRQHandler(void)
{
//I2C3 DMA transmit completed
if (DMA_GetITStatus(DMA1_Stream4, DMA_IT_TC) != RESET)
{
// Stop DMA, clear interrupt
DMA_Cmd(DMA1_Stream4, DISABLE);
DMA_ClearITPendingBit(DMA1_Stream4, DMA_IT_TC);
I2C_DMACmd(SSD1306_I2C, DISABLE);
}
}
// Sending stop condition to I2C in separate handler necessary
// because DMA can finish before I2C finishes
// transmitting and last byte is not sent
extern void I2C3_EV_IRQHandler(void)
{
if (I2C_GetITStatus(I2C3, I2C_IT_BTF) != RESET)
{
TM_I2C_Stop(SSD1306_I2C); // send i2c stop
I2C_ClearITPendingBit(I2C3, I2C_IT_BTF);
}
}
// ...
void TM_SSD1306_UpdateScreen(void) {
TM_I2C_WriteMultiDMA(&ssd1306_dma_data, SSD1306_I2C, SSD1306_I2C_ADDR, 0x40, 1024); // Use DMA
}
edit: i noticed the wrong condition checking at initializing a new transfer, but fixing it doesn't fix the main problem
while ((I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY) || !I2C_GetFlagStatus(I2Cx, I2C_FLAG_TXE) || DMA_GetCmdStatus(dmaData->DMAy_Streamx)) && TM_I2C_Timeout)

Writing SSPBUF from variable in I2C slave protocol in PIC18

I am writing an I2C slave routine for PIC18F25K80 and I am stuck on a weird problem.
This is my routine:
void interrupt interruption_handler() {
PIE1bits.SSPIE = 0; // Disable Master Synchronous Serial Port Interrupt
if (PIR1bits.SSPIF != 1) {
//This is not I2C interruption;
PIE1bits.SSPIE = 1; // Enable Master Synchronous Serial Port Interrupt
return;
}
//Treat overflow
if ((SSPCON1bits.SSPOV) || (SSPCON1bits.WCOL)) {
dummy = SSPBUF; // Read the previous value to clear the buffer
SSPCON1bits.SSPOV = 0; // Clear the overflow flag
SSPCON1bits.WCOL = 0; // Clear the collision bit
SSPCON1bits.CKP = 1;
board_state = BOARD_STATE_ERROR;
} else {
if (!SSPSTATbits.D_NOT_A) {
//Slave address
debug(0, ON);
//Read address
address = SSPBUF; //Clear BF
while(BF); //Wait until completion
if (SSPSTATbits.R_NOT_W) {
SSPCON1bits.WCOL = 0;
unsigned char a = 0x01;
SSPBUF = a;//0x01 works //Deliver first byte
asm("nop");
}
} else {
if (SSPSTATbits.BF) {
dummy = SSPBUF; // Clear BF (just in case)
while(BF);
}
if (SSPSTATbits.R_NOT_W) {
//Multi-byte read
debug(1, ON);
SSPCON1bits.WCOL = 0;
SSPBUF = 0x02; //Deliver second byte
asm("nop");
} else {
//WRITE
debug(2, ON);
}
}
transmitted = TRUE;
SSPCON1bits.CKP = 1;
PIR1bits.SSPIF = 0;
PIE1bits.SSPIE = 1; // Enable Master Synchronous Serial Port Interrupt
}
}
It works like a charm if I set constant values on SSPBUF. For example, if you do:
SSPBUF = 0x01;
(...)
SSPBUF = 0x02;
I get the two bytes on the master. I can even see the wave forms of the bytes being transmitted on the oscilloscope. Quite fun!
But when I try to set SSPBUF using a variable like:
unsigned char a = 0x01;
SSPBUF = a;
I get zero on the master.
It is driving me crazy.
Some hypothesis I've discarded:
Watchdog timer is messing up interrupting in the middle of the protocol: It is not. It is disabled and the problem happens in both SSPBUF assignments
I need to wait until BF goes low to continue: I don't. AFAIK, you setup the SSPBUF, clear SSPIF, set CKP and return from interruption to take care of life in 4Mhz while the hardware send data in few Khz. It will interrupt you again when it finishes.
It makes no sense to me. How good it is if you cannot define an arbitrary value using a variable?
Please gurus out there, enlighten this poor programmer.
Thanks in advance.
It has something to do with how the compiler generates the code and some undocumented/unknown PIC restriction around SSPBUF (it is an special register anyway).
I found out that it works when the compiler uses movwf and does not work when the compiler uses movff.
I moved the question to another forum because I realized the audience there is more adequate.
You will find more details here:
https://electronics.stackexchange.com/questions/251763/writing-sspbuf-from-variable-in-i2c-slave-protocol-in-pic18/251771#251771
Try move declaration : "unsigned char a = 0x01;"
to the beginning of the function or try define it as volatile global variable.
take into accunte that SSPBUF is both read and write buffer.check if there are conditions that may cause I2C module to reset this buffer.

c: socketCAN connection: read() not fast enough

socketCAN connection: read() not fast enough
Hello,
I use the socket() connection for my CAN communication.
fd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
I'm using 2 threads: one periodic 1ms RT thread to send data and one
thread to read the incoming messages. The read function looks like:
void readCan0Socket(void){
int receivedBytes = 0;
do
{
// set GPIO pin low
receivedBytes = read(fd ,
&receiveCanFrame[recvBufferWritePosition],
sizeof(struct can_frame));
// reset GPIO pin high
if (receivedBytes != 0)
{
if (receivedBytes == sizeof(struct can_frame))
{
recvBufferWritePosition++;
if (recvBufferWritePosition == CAN_MAX_RECEIVE_BUFFER_LENGTH)
{
recvBufferWritePosition = 0;
}
}
receivedBytes = 0;
}
} while (1);
}
The socket is configured in blocking mode, so the read function stays open
until a message arrived. The current implementation is working, but when
I measure the time between reading a message and the next waiting state of
the read function (see set/reset GPIO comment) the time varies between 30 us
(the mean value) and > 200 us. A value greather than 200us means
(CAN has a baud rate of 1000 kBit/s) that packages are not recognized while
the read() handles the previous message. The read() function must be ready within
134 us.
How can I accelerate my implementation? I tried to use two threads which are
separated with Mutexes (lock before the read() function and unlock after a
message reception), but this didn't solve my problem.

Resources