Failure in writing to EEPROM, through IC2, on PIC32MX - c

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);
}
// ----------------------------------------------------------------------------

Related

How to update the LED on a TI board and report to the server every second via UART

I am modifying a code in embedded C language and trying to make it to where it checks buttons every 200ms, checks the temperature every 500ms, and update the LED and report to the server every second. My code appears to be complete but when I run it, nothing outputs to the console, and my LED light neither turns off or on when I press either buttons on the side of the TI board. Is there something wrong with my nested while loop? Here is my code:
/*
* ======== gpiointerrupt.c ========
*/
#include <stdint.h>
#include <stddef.h>
/* Driver Header files */
#include <ti/drivers/GPIO.h>
#include <ti/drivers/I2C.h>
#include <ti/drivers/UART.h>
/* Driver configuration */
#include "ti_drivers_config.h"
/* Driver timer */
#include <ti/drivers/Timer.h>
#define TRUE 1
#define FALSE 0
#define NUMBER_OF_TASKS 3
#define GLOBAL_PERIOD 100 //milliseconds
#define DISPLAY(x) UART_write(uart, &output, x);
// UART Global Variables
char output[64];
int bytesToSend;
// Driver Handles - Global variables
UART_Handle uart;
// Init variables
int buttonCheckTime = 0;
int tempCheckTime = 0;
int displayCheckTime = 0;
int buttonCheckPeriod = 200;
int tempCheckPeriod = 500;
int displayCheckPeriod = 1000;
int setpoint = 25;
int heat = 0;
int seconds = 0;
int temperature = 0;
int firstButtonWasPressed = FALSE; // It is initally false that the button was pressed
int secondButtonWasPressed = FALSE; // It is initally false that the button was pressed
int global_period = GLOBAL_PERIOD; // Global period to be used initTimer()
void initUART(void)
{
UART_Params uartParams;
// Init the driver
UART_init();
// Configure the driver
UART_Params_init(&uartParams);
uartParams.writeDataMode = UART_DATA_BINARY;
uartParams.readDataMode = UART_DATA_BINARY;
uartParams.readReturnMode = UART_RETURN_FULL;
uartParams.baudRate = 115200;
// Open the driver
uart = UART_open(CONFIG_UART_0, &uartParams);
if (uart == NULL)
{
/* UART_open() failed */
while (1)
;
}
}
// I2C Global Variables
static const struct
{
uint8_t address;
uint8_t resultReg;
char *id;
} sensors[3] = { { 0x48, 0x0000, "11X" }, { 0x49, 0x0000, "116" }, { 0x41,
0x0001,
"006" } };
uint8_t txBuffer[1];
uint8_t rxBuffer[2];
I2C_Transaction i2cTransaction;
// Driver Handles - Global variables
I2C_Handle i2c;
// Initialize the I2C peripheral
// Make sure you call initUART() before calling this function.
void initI2C(void)
{
int8_t i, found;
I2C_Params i2cParams;
DISPLAY(snprintf(output, 64, "Initializing I2C Driver - "))
// Init the driver
I2C_init();
// Configure the driver
I2C_Params_init(&i2cParams);
i2cParams.bitRate = I2C_400kHz;
// Open the driver
i2c = I2C_open(CONFIG_I2C_0, &i2cParams);
if (i2c == NULL)
{
DISPLAY(snprintf(output, 64, "Failed\n\r"))
while (1)
;
}
DISPLAY(snprintf(output, 32, "Passed\n\r"))
// Boards were shipped with different sensors.
// Welcome to the world of embedded systems.
// Try to determine which sensor we have.
// Scan through the possible sensor addresses
/* Common I2C transaction setup */
i2cTransaction.writeBuf = txBuffer;
i2cTransaction.writeCount = 1;
i2cTransaction.readBuf = rxBuffer;
i2cTransaction.readCount = 0;
found = false;
for (i = 0; i < 3; ++i)
{
i2cTransaction.slaveAddress = sensors[i].address;
txBuffer[0] = sensors[i].resultReg;
DISPLAY(snprintf(output, 64, "Is this %s? ", sensors[i].id))
if (I2C_transfer(i2c, &i2cTransaction))
{
DISPLAY(snprintf(output, 64, "Found\n\r"))
found = true;
break;
}
DISPLAY(snprintf(output, 64, "No\n\r"))
}
if (found)
{
DISPLAY(snprintf(output, 64, "Detected TMP%s I2C address: %x\n\r",
sensors[i].id, i2cTransaction.slaveAddress))
}
else
{
DISPLAY(snprintf(output, 64,
"Temperature sensor not found, contact professor\n\r"))
}
}
int16_t readTemp(void)
{
int j;
int16_t temperature = 0;
i2cTransaction.readCount = 2;
if (I2C_transfer(i2c, &i2cTransaction))
{
/*
* Extract degrees C from the received data;
* see TMP sensor datasheet
*/
temperature = (rxBuffer[0] << 8) | (rxBuffer[1]);
temperature *= 0.0078125;
/*
* If the MSB is set '1', then we have a 2's complement
* negative value which needs to be sign extended
*/
if (rxBuffer[0] & 0x80)
{
temperature |= 0xF000;
}
}
else
{
DISPLAY(snprintf(output, 64, "Error reading temperature sensor (%d)\n\r", i2cTransaction.status))
DISPLAY(snprintf(output,64, "Please power cycle your board by unplugging USB and plugging back in.\n\r"))
}
return temperature;
}
// Driver Handles - Global variables
Timer_Handle timer0;
volatile unsigned char TimerFlag = 0;
// A single task in the task list.
struct task_entry
{
void (*f)(); // Function to call to perform the task
int elapsed_time; // Amount of time since last triggered
int period; // Period of the task in ms
char triggered; // Whether or not the task was triggered
};
// Forward declaration
void task_one();
void task_two();
void task_three();
void task_one()
{
// Processing for task_one takes place
/* Every 200ms, check button presses */
if (buttonCheckTime >= buttonCheckPeriod) // Button check time equals or exceeds period
{
if (firstButtonWasPressed == TRUE) // Button on one side raises setpoint (thermostat setting) by 1
{
setpoint += 1; // Increment thermostat
firstButtonWasPressed = FALSE; // Reset button to FALSE
}
if (secondButtonWasPressed == TRUE) // Button on the other side lowers setpoint (thermostat setting) by 1
{
setpoint -= 1; // Decrement thermostat
secondButtonWasPressed = FALSE; // Reset button to FALSE
}
}
}
void task_two()
{
// Processing for task_two takes place
if (tempCheckTime >= tempCheckPeriod) // Temperature check time equals or exceeds period
{
temperature = readTemp();
if (temperature > setpoint) {
GPIO_write(CONFIG_GPIO_LED_0, CONFIG_GPIO_LED_OFF);
heat = 0;
}
else {
GPIO_write(CONFIG_GPIO_LED_0, CONFIG_GPIO_LED_ON);
heat = 1;
}
}
}
void task_three()
{
// Processing for task_three takes place
if (displayCheckTime == displayCheckPeriod) {
DISPLAY(snprintf(output, 64, "<%02d,%02d,%d,%04d>\n\r", temperature,
setpoint, heat, seconds));
++seconds;
}
}
// The task list
struct task_entry tasks[NUMBER_OF_TASKS] = { { FALSE, &task_one, 500, 500 }, {FALSE, &task_two, 1500, 1500 }, { FALSE, &task_three, 2000, 2000 } };
void timerCallback(Timer_Handle myHandle, int_fast16_t status)
{
int x = 0;
// Walk through each task.
for (x = 0; x < NUMBER_OF_TASKS; x++)
{
// Check if task's interval has expire
if (tasks[x].elapsed_time >= tasks[x].period)
{
// Bing! This task's timer is up
// Set it's flag, and the global flag
tasks[x].triggered = TRUE;
TimerFlag = TRUE;
// Reset the elapsed_time
tasks[x].elapsed_time = 0;
}
else
{
tasks[x].elapsed_time += global_period;
}
}
}
void initTimer(void)
{
Timer_Params params;
// Init the driver
Timer_init();
// Configure the driver
Timer_Params_init(&params);
params.period = 1000000;
params.periodUnits = Timer_PERIOD_US;
params.timerMode = Timer_CONTINUOUS_CALLBACK;
params.timerCallback = timerCallback;
// Open the driver
timer0 = Timer_open(CONFIG_TIMER_0, &params);
if (timer0 == NULL)
{
/* Failed to initialized timer */
while (1)
{
}
}
if (Timer_start(timer0) == Timer_STATUS_ERROR)
{
/* Failed to start timer */
while (1)
{
}
}
}
/*
* ======== gpioButtonFxn0 ========
* Callback function for the GPIO interrupt on CONFIG_GPIO_BUTTON_0.
*
* Note: GPIO interrupts are cleared prior to invoking callbacks.
*/
void gpioButtonFxn0(uint_least8_t index)
{
/* Toggle an LED */
//GPIO_toggle(CONFIG_GPIO_LED_0);
firstButtonWasPressed = TRUE; // It is true that the button was pressed
}
/*
* ======== gpioButtonFxn1 ========
* Callback function for the GPIO interrupt on CONFIG_GPIO_BUTTON_1.
* This may not be used for all boards.
*
* Note: GPIO interrupts are cleared prior to invoking callbacks.
*/
void gpioButtonFxn1(uint_least8_t index)
{
/* Toggle an LED */
//GPIO_toggle(CONFIG_GPIO_LED_1);
secondButtonWasPressed = TRUE;
}
/*
* ======== mainThread ========
*/
void* mainThread(void *arg0)
{
/* Call driver init functions */
GPIO_init();
/* Configure the LED and button pins */
GPIO_setConfig(CONFIG_GPIO_LED_0, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
//GPIO_setConfig(CONFIG_GPIO_BUTTON_0;
//GPIO_CFG_IN_PU | GPIO_CFG_IN_INT_FALLING);
/* Turn on user LED */
GPIO_write(CONFIG_GPIO_LED_0, CONFIG_GPIO_LED_ON);
/* Install Button callback */
GPIO_setCallback(CONFIG_GPIO_BUTTON_0, gpioButtonFxn0);
/* Enable interrupts */
GPIO_enableInt(CONFIG_GPIO_BUTTON_0);
/*
* If more than one input pin is available for your device, interrupts
* will be enabled on CONFIG_GPIO_BUTTON1.
*/
if (CONFIG_GPIO_BUTTON_0 != CONFIG_GPIO_BUTTON_1)
{
/* Configure BUTTON1 pin */
GPIO_setConfig(CONFIG_GPIO_BUTTON_1,
GPIO_CFG_IN_PU | GPIO_CFG_IN_INT_FALLING);
/* Install Button callback */
GPIO_setCallback(CONFIG_GPIO_BUTTON_1, gpioButtonFxn1);
/* Enable interrupts */
GPIO_enableInt(CONFIG_GPIO_BUTTON_1);
}
// Call driver init functions
initUART(); // The UART must be initialized before calling initI2C()
initI2C();
initTimer();
// Loop Forever
while (TRUE)
{
readTemp();
// Every 200ms check the button flags
task_one();
// Every 500ms read the temperature and update the LED
task_two();
// Every second output the following to the UART
// "<%02d,%02d,%d,%04d>, temperature, setpoint, heat, seconds
task_three();
// Wait for task intervals (periods) to elapse
while (!TimerFlag)
{
} // Wait for timer period
// Process the tasks for which the interval has expired
int x = 0;
for (x = 0; x < NUMBER_OF_TASKS; x++)
{
if (tasks[x].triggered)
{
tasks[x].f();
// reset
tasks[x].triggered = FALSE;
}
}
// Reset everything (e.g. flags) and go back to the beginning
TimerFlag = FALSE; // Lower flag raised by timer
++global_period;
}
}

HAL_UART_Transmit_IT sending data twice

I am trying to establish UART communication between a PC and a STM32f407-DISC1 board using an arduino nano as a middle man.
The PC sends 'r' to the arduino to indicate a request.
The request is then communicated to the stm32 with a GPIO interrupt, which then should be transmitting 480 bytes of data using HAL_UART_Transmit_IT.
It however sends the data twice, with only a single request made.
The code on the STM32 is generated by STM32CubeMX
Data request made by the arduino
void loop() {
digitalWrite(4, 0); // Clear EXTI11 line.
if (mySerial.available() && received < 480) { // STM32 sending data and is not done.
buff[received] = mySerial.read(); // Append received data to the buffer.
received++;
}
if (received >= 480) { // If the buffer is full
received = 0; // transmit it to PC.
Serial.println(buff);
}
if (Serial.available()) {
if (Serial.read() == 'r') { // PC requests data from the STM32
digitalWrite(4, 1); // Triggers STM32 EXTI11 line.
while (Serial.available()) // Empty the buffer.
Serial.read();
}
}
}
data transmission on the STM32
void EXTI15_10_IRQHandler(void)
{
// Make sure that the interrupt is the good one.
if (HAL_GPIO_ReadPin(data_req_IRQ_GPIO_Port, data_req_IRQ_Pin)) {
if (is_sending_data == FALSE) // If no transmission is happening
should_send_data = TRUE; // raise transmission flag.
}
// IRQ handling stuff...
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef * huart) {
is_sending_data = FALSE; // Transmition is completed, unblock requests.
}
void main(void){
// Init and other stuff...
while (1) {
if (should_send_data == TRUE) { // If data was requested
HAL_GPIO_WritePin(LD5_GPIO_Port, LD5_Pin, GPIO_PIN_RESET);
HAL_UART_Transmit_IT(&huart3, matrice, 480); // Start transmission by interrupt.
is_sending_data = TRUE; // Block requests.
should_send_data = FALSE; // Clear flag.
}
// matrice acquisition stuff here
}
}
Alright so I found a solution, but it involved just rethinking my approach, so sorry for those looking for an answer to this problem.
I removed the arduino middle man by replacing it with a USB to RS232 converter and made UART reception work by interrupt. The STM detects the 'r' character which triggers the data communication.
Here is the interrupt part:
void USART3_IRQHandler(void)
{
if (USART3->SR & UART_IT_RXNE) { // If a byte is received
rxBuff[0] = (uint8_t) (huart3.Instance->DR & (uint8_t) 0xFF); // Read it.
__HAL_UART_FLUSH_DRREGISTER(&huart3); // Clear the buffer to avoid errors.
rx_new_char_flag = TRUE; // Raise the new_char flag.
return; // Stops the IRQHandler from disabling interrupts.
}
}
and the gestion of that in the main
while (1) {
if (rx_new_char_flag == TRUE) {
rx_new_char_flag = FALSE;
if (rxBuff[0] == 'r') {
rxBuff[0] = 0;
HAL_UART_Transmit_IT(&huart3, matrice, 480); // Start transmission by interrupt.
}
}
On the PC side, to optimize performance, instead of waiting for the full 480 bytes, I wait for only one character, if one is received I keep reading the serial port, as shown in the code bellow
int i = 0;
do {
ReadFile(m_hSerial, &temp_rx[i], 1, &dwBytesRead, NULL);
i++;
} while (dwBytesRead > 0 && i < 480);
for (int j = i; j < 480; j++) // If the transmission is incomplete, fill the buffer with 0s to avoid garbage data.
temp_rx[j] = 0;
if(i>=480) // If all the bytes has been received, copy the data in the working buffer.
std::copy(std::begin(temp_rx), std::end(temp_rx), std::begin(m_touch_state));
This works well with pretty decent performance, so that may be a permanent solution to my problem.

How to continuos transmit data?

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
}

STM32 USB OTG HOST Library hangs trying to create file with FatFs

I am trying to create a file with FatFs on USB flash, but my f_open call trying to read boot sector for first time file system mount hangs on this function.
DRESULT disk_read (
BYTE drv, /* Physical drive number (0) */
BYTE *buff, /* Pointer to the data buffer to store read data */
DWORD sector, /* Start sector number (LBA) */
BYTE count /* Sector count (1..255) */
)
{
BYTE status = USBH_MSC_OK;
if (drv || !count) return RES_PARERR;
if (Stat & STA_NOINIT) return RES_NOTRDY;
if(HCD_IsDeviceConnected(&USB_OTG_Core))
{
do
{
status = USBH_MSC_Read10(&USB_OTG_Core, buff,sector,512 * count);
USBH_MSC_HandleBOTXfer(&USB_OTG_Core ,&USB_Host);
if(!HCD_IsDeviceConnected(&USB_OTG_Core))
{
return RES_ERROR;
}
}
while(status == USBH_MSC_BUSY ); // Loop which create hanging state
}
if(status == USBH_MSC_OK)
return RES_OK;
return RES_ERROR;
}
The main problem is the loop which creates hanging state
while(status == USBH_MSC_BUSY );
So I do not know what to do to avoid this. Using debugger I discover that state is caused by parameter CmdStateMachine of structure USBH_MSC_BOTXferParam, type USBH_BOTXfer_TypeDef is equal CMD_UNINITIALIZED_STATE which actually cause miss up of switch statement of USBH_MSC_Read10 function.
/**
* #brief USBH_MSC_Read10
* Issue the read command to the device. Once the response received,
* it updates the status to upper layer
* #param dataBuffer : DataBuffer will contain the data to be read
* #param address : Address from which the data will be read
* #param nbOfbytes : NbOfbytes to be read
* #retval Status
*/
uint8_t USBH_MSC_Read10(USB_OTG_CORE_HANDLE *pdev,
uint8_t *dataBuffer,
uint32_t address,
uint32_t nbOfbytes)
{
uint8_t index;
static USBH_MSC_Status_TypeDef status = USBH_MSC_BUSY;
uint16_t nbOfPages;
status = USBH_MSC_BUSY;
if(HCD_IsDeviceConnected(pdev))
{
switch(USBH_MSC_BOTXferParam.CmdStateMachine)
{
case CMD_SEND_STATE:
/*Prepare the CBW and relevant field*/
USBH_MSC_CBWData.field.CBWTransferLength = nbOfbytes;
USBH_MSC_CBWData.field.CBWFlags = USB_EP_DIR_IN;
USBH_MSC_CBWData.field.CBWLength = CBW_LENGTH;
USBH_MSC_BOTXferParam.pRxTxBuff = dataBuffer;
for(index = CBW_CB_LENGTH; index != 0; index--)
{
USBH_MSC_CBWData.field.CBWCB[index] = 0x00;
}
USBH_MSC_CBWData.field.CBWCB[0] = OPCODE_READ10;
/*logical block address*/
USBH_MSC_CBWData.field.CBWCB[2] = (((uint8_t*)&address)[3]);
USBH_MSC_CBWData.field.CBWCB[3] = (((uint8_t*)&address)[2]);
USBH_MSC_CBWData.field.CBWCB[4] = (((uint8_t*)&address)[1]);
USBH_MSC_CBWData.field.CBWCB[5] = (((uint8_t*)&address)[0]);
/*USBH_MSC_PAGE_LENGTH = 512*/
nbOfPages = nbOfbytes/ USBH_MSC_PAGE_LENGTH;
/*Tranfer length */
USBH_MSC_CBWData.field.CBWCB[7] = (((uint8_t *)&nbOfPages)[1]) ;
USBH_MSC_CBWData.field.CBWCB[8] = (((uint8_t *)&nbOfPages)[0]) ;
USBH_MSC_BOTXferParam.BOTState = USBH_MSC_SEND_CBW;
/* Start the transfer, then let the state machine
manage the other transactions */
USBH_MSC_BOTXferParam.MSCState = USBH_MSC_BOT_USB_TRANSFERS;
USBH_MSC_BOTXferParam.BOTXferStatus = USBH_MSC_BUSY;
USBH_MSC_BOTXferParam.CmdStateMachine = CMD_WAIT_STATUS;
status = USBH_MSC_BUSY;
break;
case CMD_WAIT_STATUS:
if((USBH_MSC_BOTXferParam.BOTXferStatus == USBH_MSC_OK) && \
(HCD_IsDeviceConnected(pdev)))
{
/* Commands successfully sent and Response Received */
USBH_MSC_BOTXferParam.CmdStateMachine = CMD_SEND_STATE;
status = USBH_MSC_OK;
}
else if (( USBH_MSC_BOTXferParam.BOTXferStatus == USBH_MSC_FAIL ) && \
(HCD_IsDeviceConnected(pdev)))
{
/* Failure Mode */
USBH_MSC_BOTXferParam.CmdStateMachine = CMD_SEND_STATE;
}
else if ( USBH_MSC_BOTXferParam.BOTXferStatus == USBH_MSC_PHASE_ERROR )
{
/* Failure Mode */
USBH_MSC_BOTXferParam.CmdStateMachine = CMD_SEND_STATE;
status = USBH_MSC_PHASE_ERROR;
}
else
{
/* Wait for the Commands to get Completed */
/* NO Change in state Machine */
}
break;
default:
break;
}
}
return status;
}
Here is USBH_BOTXfer_TypeDef type declaration;
typedef struct _BOTXfer
{
uint8_t MSCState;
uint8_t MSCStateBkp;
uint8_t MSCStateCurrent;
uint8_t CmdStateMachine;
uint8_t BOTState;
uint8_t BOTStateBkp;
uint8_t* pRxTxBuff;
uint16_t DataLength;
uint8_t BOTXferErrorCount;
uint8_t BOTXferStatus;
} USBH_BOTXfer_TypeDef;
During the debug I discover that all fields of it is 0x00.
Here are my FatFs calls
int main(void)
{
FATFS Fat;
FIL file;
FRESULT fr;
RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN;
/* Enable SWO output */
DBGMCU->CR = 0x00000020;
GPIOD->MODER=0x55000000;
GPIOD->OTYPER = 0x00000000;
GPIOD->OSPEEDR = 0x00000001;
while(1)
{
if (!USB_MSC_IsInitialized())
{
USB_MSC_Initialize();
}
if (USB_MSC_IsConnected())
{
GPIOD->ODR = (1 << 15);
disk_initialize(0);
fr = f_mount(0, &Fat);
if(fr == FR_OK)
{
fr = f_open(&file,"0:DP_lab8.pdf",(FA_CREATE_ALWAYS | FA_WRITE));
if (fr == FR_OK)
{
f_close(&file);
}
f_mount(0, NULL);
}
}
else
{
GPIOD->ODR = (1 << 14);
}
USB_MSC_Main();
}
}
USB_MSC_IsConnected function is:
int USB_MSC_IsConnected(void)
{
if (g_USB_MSC_HostStatus == USB_DEV_NOT_SUPPORTED)
{
USB_MSC_Uninitialize();
}
return !(g_USB_MSC_HostStatus == USB_DEV_DETACHED ||
g_USB_MSC_HostStatus == USB_HOST_NO_INIT ||
g_USB_MSC_HostStatus == USB_DEV_NOT_SUPPORTED);
}
And device states are:
typedef enum
{
USB_HOST_NO_INIT = 0, /* USB interface not initialized */
USB_DEV_DETACHED, /* no device connected */
USB_SPEED_ERROR, /* unsupported USB speed */
USB_DEV_NOT_SUPPORTED, /* unsupported device */
USB_DEV_WRITE_PROTECT, /* device is write protected */
USB_OVER_CURRENT, /* overcurrent detected */
USB_DEV_CONNECTED /* device connected and ready */
} USB_HostStatus;
The value of g_USB_MSC_HostStatus is received by standard USB HOST user callbacks.
I think it is a bug in ST host library. I've hunted it down, as my usb host was unable to pass enumeration stage. After a fix the stack is Ok.
There is union _USB_Setup in usbh_def.h file in "STM32Cube/Repository/STM32Cube_FW_F7_V1.13.0/Middlewares/ST/STM32_USB_Host_Library/Core/Inc" (any chip, not only F7, any version, not only V1.13.0). It has uint16_t bmRequestType and uint16_t bRequest. These two fileds must be uint8_t as of USB specs. Fixing this issue made usb host go as needed. Enumeration stage passes ok, and all other stages as well.

No response from UART

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.

Resources