Communication with SD Card with STM32 Processor - SDIO protocol - c

I am using the board Nucleo F401Re based on micro-controller STM32F401RET6. I connected to the board a Micro SD slot, and interested in writing data to the SD Card and read data from it. I used the software STM32CubeX to generate code and in particular the SD library with built-in functions. I tried to write a simple code which writes an array to a specific array and tries to read the same data afterwords. The code is as follows:
int main(void)
{
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART2_UART_Init();
MX_SDIO_SD_Init();
char buffer[14] = "Hello, world\n";
uint32_t to_send[512] ; // Te
uint32_t to_receive[512];
uint64_t address = 150;
HAL_SD_WriteBlocks(&hsd, to_send, address, 512, 1);
HAL_SD_ReadBlocks(&hsd, to_receive, address, 512, 1);
while (1)
{
HAL_UART_Transmit(&huart2, (uint8_t *)buffer, 14, 1000);
HAL_UART_Transmit(&huart2, (uint8_t *)to_receive, 512, 1000);
}
The code stopps in the middle of the function HAL_Init() and I'm getting the following message:
The stack pointer for stack 'CSTACK' (currently 0x1FFFFD30) is outside the stack range (0x20000008 to 0x20000408)
This message doesn't appear when I don't use the functions HAL_SD_WriteBlocks(), or HAL_SD_ReadBlocks(). If someone already had this problem and knows how to fix it, some help would save me. If needed I can add the rest of the code.

You're using too much stack space. You can adjust the allocated stack space in the linker script and increase it if needed.
However you can probably avoid that by writing your code differently. In your example above, you're allocating large buffers (4kB) on the stack. Don't do that unless absolutely necessary. I'm referring to this:
int main(void) {
// ...
uint32_t to_send[512];
uint32_t to_receive[512];
// ...
}
Instead, allocate your buffers like this:
uint32_t to_send[512];
uint32_t to_receive[512];
int main(void) {
// ...
}

Related

Calling bluetooth commands freezes the coprocessor

I am trying to influence payload inside BLE advertisement beacons. My dev board is NUCLEO WB16CC based on a dual core STM32WB15CC.
Whenever I try to aci_gap_update_adv_data(sizeof(manuf_data), manuf_data); the program hangs between the // LED lines which I have added:
static void SendCmd(uint16_t opcode, uint8_t plen, void *param)
{
// vorac
HAL_GPIO_WritePin(0x48000400, ((uint16_t)0x0020), 0); // LED1
pCmdBuffer->cmdserial.cmd.cmdcode = opcode;
HAL_GPIO_WritePin(0x48000400, ((uint16_t)0x0001), 0); // LED2
pCmdBuffer->cmdserial.cmd.plen = plen;
memcpy( pCmdBuffer->cmdserial.cmd.payload, param, plen );
hciContext.io.Send(0,0);
return;
}
pCmdBuffer is not null it actually points to PLACE_IN_SECTION("MB_MEM1") ALIGN(4) static TL_CmdPacket_t BleCmdBuffer;.
If that is changed to an ordinary global variable, the problem shifts down to the hciContext.io.Send(0,0); line.
I suspect some problem with the inter process communication but can't phantom where to look. Suggestions?
Sounds to me that the value in pCmdBuffer is not aligned, and the processor requires strict alignment.

Why there is a word address in this I2C example code from FTDI?

I have been working on FTDI FT2232H chip to interface with I2C devices. I have started to learn AN_177 application note pdf. I have no EEPROM to expreience,no oscilloscope to see waveforms. My goal is to comprehend the code itself and taking notes for my future projects. Here is the code snippet that i dont completely understand:
FT_STATUS write_byte(uint8 slaveAddress, uint8 registerAddress, uint8 data)
{
uint32 bytesToTransfer = 0;
uint32 bytesTransfered;
bool writeComplete=0;
uint32 retry=0;
bytesToTransfer=0;
bytesTransfered=0;
buffer[bytesToTransfer++]=registerAddress; /* Byte addressed inside EEPROM */
buffer[bytesToTransfer++]=data;
status = I2C_DeviceWrite(ftHandle, slaveAddress, bytesToTransfer, buffer, &bytesTransfered, I2C_TRANSFER_OPTIONS_START_BIT|I2C_TRANSFER_OPTIONS_STOP_BIT);
/* poll to check completition */
while((writeComplete==0)&& (retry<I2C_WRITE_COMPLETION_RETRY))
{
bytesToTransfer=0;
bytesTransfered=0;
buffer[bytesToTransfer++]=registerAddress; /* Addressed inside EEPROM */
status = I2C_DeviceWrite(ftHandle, slaveAddress, bytesToTransfer,buffer, &bytesTransfered, I2C_TRANSFER_OPTIONS_START_BIT|I2C_TRANSFER_OPTIONS_BREAK_ON_NACK);
if((FT_OK == status) && (bytesToTransfer == bytesTransfered))
{
writeComplete=1;
printf(" ... Write done\n");
}
retry++;
}
return status;
}
You can see and understand that the while loop is the polling part.
I checked the datasheet of 24LC024H I2C EEPROM and they mentioned about Acknowladge Polling (Page 10) is a feature of this kind of EEPROMs'. Acknowladge Polling basicly checks when the device is ready to send data. There is a flow diagram too... you could take a look.
Flowchart
Here comes the what i want to point out:
buffer[bytesToTransfer++]=registerAddress; /* Addressed inside EEPROM */
In the 24LC024H datasheet related to Acknowladge Polling they say polling part consist of START + Control Byte (or Slave address) + R/W bit, not include address inside EEPROM (Word address in I2C protocol) . So why FTDI guys included this line of code? Am I missing something?
Best regards...

Array's data is changed if I don't printf it

I am writing a C program on Eclipse to communicate from my ARM Cortex M4-F microcontroller in I2C with its master, another MCU.
In my I2C library, I use a static global variable to store all the parameters of the communication (address, lenghts, data buffers). The issue is that a part (an array containing the data to be transmitted, which are 8 bits integers) of this variable gets modified when the interrupt (Start condition followed by the slave's address on the I2C bus) happens, even before executing the code I put the handler. It gets assigned to 8, whatever the initial value.
I tried to put breakpoints basically everywhere, and a watchpoint on the variable, the changes arises seemingly from nowhere, not in the while loop, and before the call to my_I2C_Handler(), so the interrupt is the cause apparently.
I also tried setting the variable as volatile, but that changed nothing.
I noticed one interesting thing: putting a printf of the array's data during my_I2C_Init() or my_SlaveAsync(), like so:
printf("%d\n", req.tx_data[0]);
corrects this problem, but why? I want to remove all prints after debugging.
#include <stdint.h>
#include "my_i2c.h"
void I2C1_IRQHandler(void)
{
printf("\nI2C Interrupt\n");
my_I2C_Handler(MXC_I2C1); // MXC_I2C1 is a macro for the registry used
}
int main(void)
{
int error = 0;
printf("\nStarting I2C debugging\n");
// Setup the I2C
my_I2C_Shutdown(MXC_I2C1);
my_I2C_Init(MXC_I2C1);
NVIC_EnableIRQ(I2C1_IRQn); // Enable interrupt
my_I2C_SlaveAsync(MXC_I2C1); // Prepare to receive communication
while (1)
{
LED_On(0);
LED_Off(0);
}
printf("\nDone testing\n");
return 0;
}
The structure of the request containing the parameters of the communication is like this:
typedef struct i2c_req i2c_req_t;
struct i2c_req {
uint8_t addr; // I2C 7-bit Address
unsigned tx_len; // Length of tx data
unsigned rx_len; // Length of rx
unsigned tx_num; // Number of tx bytes sent
unsigned rx_num; // Number of rx bytes sent
uint8_t *tx_data; // Data for mater write/slave read
uint8_t *rx_data; // Data for master read/slave write
};
Is declared like so in the beginning of the file:
static i2c_req_t req;
and assigned this way in my_I2C_Init():
uint8_t rx[1] = {0};
uint8_t tx[1] = {12};
req.addr = 0xAA;
req.tx_data = tx;
req.tx_len = 1;
req.rx_data = rx;
req.rx_len = 1;
req.tx_num = 0;
req.rx_num = 0;
Many thanks for your help

GPS UART data written multiple times to Buffer

I am receiving/reading data from a GPS module sent via USART3 to the STM32F091.
The data gets there just fine which I confirm by sending it to my PC COM3 port and feeding it to 'u-center' (GPS evaulation software).
My problem is that I want to evaluate the data myself in my C program, and for that purpose I feed it into a Ring Buffer, however, every character of the GPS signal is written multiple times to the buffer, instead of one by one.
For example
GGGGGGGPPPPPPPPSSSSSSSS instead of GPS
I am unsure what I'm doing wrong, maybe it's something really obvious I'm overlooking after staring at this code so long.
Here's the relevant code.
stm32f0xx_it.c
#include <main.h>
void USART3_8_IRQHandler(void)
{
if (USART_FLAG_RXNE != RESET)
{
uint16_t byte = 0;
/* Data reception */
/* Clear Overrun Error Flag, necessary when RXNE is used */
USART_GetITStatus(USART3, USART_IT_ORE);
/* Read from Receive Data Register and put into byte */
byte = USART_ReceiveData(USART3);
(*pRXD3).wr = ((*pRXD3).wr + 1) % (*pRXD3).max;
(*pRXD3).Buffer[(*pRXD3).wr] = byte;
/* Send Data to PC, and reset Transmission Complete Flag */
USART_GetITStatus(USART1, USART_IT_TC);
USART_SendData(USART1, byte);
return;
}
return;
}
uartGPS.h
....
struct GPSuart
{
BYTE Buffer[255];
WORD max;
WORD re;
WORD wr;
};
....
main.h
....
extern volatile BYTE B_ser_txd_3[255];
extern volatile BYTE B_ser_rxd_3[255];
extern volatile struct GPSuart TXD_uart_3;
extern volatile struct GPSuart RXD_uart_3;
extern volatile struct GPSuart *pRXD3;
extern volatile struct GPSuart *pTXD3;
....
Let me know if I should provide additional information.
This:
if (USART_FLAG_RXNE != RESET)
does not test a flag, that code is inspecting the flag constant itself, which is not what you meant.
You need more code, to access the UART's status register and check the flag:
if (USART_GetFlagStatus(USARTx, USART_FLAG_RXNE) != RESET)

How to share a hardware abstraction struct without making it global

This is a question about sharing data that is "global", mimicking a piece of addressable memory that any function could access.
I'm writing code for an embedded project, where I've decoupled my physical gpio pins from the application. The application communicates with the "virtual" gpio port, and device drivers then communicate with the actual hardware. The primary motivation for this is the comfort it allows me in switching out what pins are connected to what peripheral when developing, and to include things like button matrices that use fewer physical pins while still handling them as regular gpio device registers.
typedef struct GPIO_PinPortPair
{
GPIO_TypeDef *port; /* STM32 GPIO Port */
uint16_t pin; /* Pin number */
} GPIO_PinPortPair;
typedef struct GPIO_VirtualPort
{
uint16_t reg; /* Virtual device register */
uint16_t edg; /* Flags to signal edge detection */
GPIO_PinPortPair *grp; /* List of physical pins associated with vport */
int num_pins; /* Number of pins in vport */
} GPIO_VirtualPort;
This has worked well in the code I've written so far, but the problem is that I feel like I have to share the addresses to every defined virtual port as a global. A function call would look something like this, mimicking the way it could look if I were to use regular memory mapped io.
file1.c
GPIO_VirtualPort LEDPort;
/* LEDPort init code that associates it with a list of physical pins */
file2.c
extern GPIO_VirtualPort LEDPort;
vgpio_write_pin(&LEDPort, PIN_1, SET_PIN);
I've searched both SO and the internet for best practices when it comes to sharing variables, and I feel like I understand why I should avoid global variables (no way to pinpoint where in code something happens to the data) and that it's better to use local variables with pointers and interface functions (like a "get current tick" function rather than reading a global tick variable).
My question is, given that I want to the keep the syntax as simple as possible, what is the best way to define these struct variables and then make them available for functions in other modules to use? Is it okay to use these struct variables as globals? Should I use some kind of master-array of pointers to every virtual port I have and use a getter function to avoid using extern variables?
I like to do it this way:
file1.h
typedef enum
{
VirtualPortTypeLED
} VirtualPortType;
typedef struct GPIO_PinPortPair
{
GPIO_TypeDef *port; /* STM32 GPIO Port */
uint16_t pin; /* Pin number */
} GPIO_PinPortPair;
typedef struct GPIO_VirtualPort
{
uint16_t reg; /* Virtual device register */
uint16_t edg; /* Flags to signal edge detection */
GPIO_PinPortPair *grp; /* List of physical pins associated with vport */
int num_pins; /* Number of pins in vport */
} GPIO_VirtualPort;
file1.c
GPIO_VirtualPort LEDPort;
void VirtualPortInit()
{
/* fill in all structures and members here */
LEDPort.reg = 0x1234;
...
}
GPIO_VirtualPort *VirtualPortGet(VirtualPortType vpt)
{
switch(vpt) {
case VirtualPortTypeLED:
return &LEDPort;
}
return NULL;
}
file2.c
#include file1.h
GPIO_VirtualPort *myLed;
VirtualPortInit();
myLed = VirtualPortGet(VirtualPortTypeLED);
Btw, I didn't compile this ... :)
To do this without using a global struct that references a given set of hardware or a global set of addresses you create a handle to the GPIO struct at the location that you want when starting out.
I'm not sure how the STM32 is laid out as I have no experience with that family of devices but I have seen and used this method in the situation you describe.
If your hardware is located at a particular address in memory, eg: 0x50, then your calling code asks a GPIO_Init() to give it a handle to the memory at that location. This still allows you to assign the struct at different locations if you need, for example:
/* gpio.h */
#include <stdef.h>
#include <stdint.h>
#include <bool.h>
typedef struct GPIO_Port GPIO_Port; // forward declare the struct definition
GPIO_Port *GPIO_Init(void *memory, const size_t size);
GPIO_Write_Pin(GPIO_Port *port_handle, uint8_t pin number, bool state);
A simple implementation of the GPIO_Init() function might be:
/* gpio.c */
#include "gpio.h"
struct GPIO_Port // the memory mapped struct definition
{
uint16_t first_register;
uint16_t second_register;
// etc, ordered to match memory layout of GPIO registers
};
GPIO_Port *GPIO_Init(void *memory, const size_t size)
{
// if you don't feel the need to check this then the
// second function parameter probably won't be necessary
if (size < sizeof(GPIO_Port *))
return (GPIO_Port *)NULL;
// here you could perform additional operations, e.g.
// clear the memory to all 0, depending on your needs
// return the handle to the memory the caller provided
return (GPIO_Port *)memory;
}
GPIO_Write_Pin(GPIO_Port *port_handle, uint8_t pin number, bool state)
{
uint16_t mask = 1u << pin_number;
if (state == true)
port_handle->pin_register |= mask; // set bit
else
port_handle->pin_register &= ~mask; // clear bit
}
Where the struct itself is defined only within the source file and there is no single global instance. Then you can use this like:
// this can be defined anywhere, or for eg, returned from malloc(),
// as long as it can be passed to the init function
#define GPIO_PORT_START_ADDR (0x50)
// get a handle at whatever address you like
GPIO_Port *myporthandle = GPIO_init(GPIO_PORT_START_ADDR, sizeof(*myporthandle));
// use the handle
GPIO_Write_Pin(myporthandle, PIN_1, SET_HIGH);
For the init function you can pass in the address of the memory with the real hardware location of the GPIO registers, or you can allocate some new block of RAM and pass the address of that.
Your addresses of the used memory do not have to be global, they are just passed to GPIO_Init() from the calling code and so ultimately could come from anywhere, the object handle takes over any subsequent referencing to that chunk of memory by passing to subsequent GPIO function calls. You should be able to build up your more complex functions around this idea of passing in the information that changes and the abstracted mapped memory such that you can still allow the functionality you mention with the "virtual" port.
This method has the benefit of separation of concerns (your GPIO unit is concerned only with the GPIO, not memory, something else can handle that), encapsulation (only the GPIO source needs to concern itself with the members of the GPIO port struct) and no/few globals (the handle can be instantiated and passed around as needed).
Personally I find this pattern pretty handy when it comes to unit testing. In release I pass the address for the real hardware but in test I pass an address for a struct somewhere in memory and test that the members are changed as expected by the GPIO unit - no hardware involved.

Resources