cancel
Showing results for 
Search instead for 
Did you mean: 

Incorrect value when reading GPIOB->IDR

OUnsa
Associate II

Hello,

I have really strange behavior while reading the input port and sending the data via BLE. I have upgraded the firmware to v1.8 and I was using the BLEDataThroughput example as a base of my project. My aim is as follows

  1. increasing the MTU size to 200bytes
  2. reading the GPIOB->IDR and store it into array (output_data) when an interrupt occurs
  3. Repeat step 2 12500 times
  4. Send the output_data via BLE

I can successfully establish the data and send the values to the smartphone. However, the data becomes all zeros even if some input is actually high.

In order to expalin it clearer, I am sharing my implementations as well. Here is my interrupt handler under stm32wbxx_it.c

void EXTI3_IRQHandler(void)
{
	// Clear the interrupt flag
    EXTI->PR1 = GPIO_PIN_3;
    GPIOC->BSRR = (uint32_t)GPIO_PIN_5;
    *p_data =  GPIOB->IDR;
    p_data++;
    counter++;
    GPIOC->BRR = (uint32_t)GPIO_PIN_5;
    if (counter == 12500) { 
    	HAL_GPIO_WritePin(START_GPIO_Port, START_Pin, GPIO_PIN_RESET);
    	HAL_GPIO_WritePin(ACK_GPIO_Port, ACK_Pin, GPIO_PIN_RESET);
    	p_data = &output_data[0];
    	counter = 0;
    	global_count++;
    	UTIL_SEQ_SetTask(1 << CFG_TASK_BUTTON_ID, CFG_SCH_PRIO_0);
    }
}

In my bluetooth application source code, I am checking the CFG_TASK_BUTTON_ID flag as following;

typedef struct
{
	SNAPSHOT_STM_Payload_t TxData;
	SNAPSHOT_App_Transfer_Req_Status_t NotificationTransferReq;
	SNAPSHOT_App_Flow_Status_t DtFlowStatus;
	uint8_t data[25000];
} SNAPSHOT_App_Context_t;
SNAPSHOT_App_Context_t DataTransferServerContext;
 
extern uint16_t output_data[12500];
static uint8_t Notification_Data_Buffer[200];
uint8_t count = 0;
 
void SNAPSHOT_App_Init(void)
{
  UTIL_SEQ_RegTask( 1<<CFG_TASK_SEND_DATA_ID, UTIL_SEQ_RFU, SendData);
  UTIL_SEQ_RegTask( 1<<CFG_TASK_BUTTON_ID, UTIL_SEQ_RFU, DataReady);
 
  /**
   * Initialize data buffer
   */
  DataTransferServerContext.NotificationTransferReq = SNAPSHOT_APP_TRANSFER_REQ_OFF;
  DataTransferServerContext.DtFlowStatus = SNAPSHOT_APP_FLOW_ON;
  memset(DataTransferServerContext.data, 0, 25000);
}
 
static void SendData( void )
{
  tBleStatus status = BLE_STATUS_INVALID_PARAMS;
  if( (DataTransferServerContext.NotificationTransferReq != SNAPSHOT_APP_TRANSFER_REQ_OFF)
      && (DataTransferServerContext.DtFlowStatus != SNAPSHOT_APP_FLOW_OFF) && count < 125)
  {
    /*Data Packet to send to remote*/
	memcpy(Notification_Data_Buffer, &DataTransferServerContext.data[count*200], 200);
        // Two lines below are for tracking how many times the transmission is handled
	Notification_Data_Buffer[0] = count;
	Notification_Data_Buffer[199] = global_count;
	DataTransferServerContext.TxData.pPayload = Notification_Data_Buffer;
	DataTransferServerContext.TxData.Length = 200;
	status = SNAPSHOT_STM_App_Update_Char(DATA_TRANSFER_TX_CHAR_UUID, (uint8_t *) &DataTransferServerContext.TxData);
	if (status == BLE_STATUS_INSUFFICIENT_RESOURCES) {
		DataTransferServerContext.DtFlowStatus = SNAPSHOT_APP_FLOW_OFF;
	} else {
		count++;
		UTIL_SEQ_SetTask(1 << CFG_TASK_SEND_DATA_ID, CFG_SCH_PRIO_0);
	}
  }
  return;
}
 
void DataReady( void )
{
  count = 0;
  memcpy(DataTransferServerContext.data, (uint8_t*)&(output_data), 25000);
  UTIL_SEQ_SetTask(1 << CFG_TASK_SEND_DATA_ID, CFG_SCH_PRIO_0);
  return;
}

I am sure that on PORTB there are some input data and I am expecting to see a value different than all zeros.

I thought maybe I am doing something wrong in BLE part and change the line   *p_data = 0xFFFF; then I was able to see the all 0xFFFF in received data. So, BLE transmission seems working, however, I couldn't figure out why *p_data = GPIOB->IDR returns zeros.

I am stucking in this point and I have no idea what could be the reason. I would be really great if someone can help me.

Best regards,

Ozan

8 REPLIES 8
Remi QUINTIN
ST Employee

Considering that the BLE part is functional, we should focus on the GPIO configuration.

This part is not exposed but I assume you set it as simple GPIO port in input mode with no alternate function enable.

What are the expected value on the GPIO port B?

I see you are surrounding the reading of the GPIO port B by the set and reset of the PIN 5 of the GPIO port C. any reason?

OUnsa
Associate II

I can also share the GPIO configuration as well.

static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
 
  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOE_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();
 
  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOC, START_Pin|ACK_Pin|MAX2771_SHDN_Pin, GPIO_PIN_RESET);
 
  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOD, PD0_Pin|PD1_Pin, GPIO_PIN_RESET);
 
  /*Configure GPIO pins : START_Pin ACK_Pin MAX2771_SHDN_Pin */
  GPIO_InitStruct.Pin = START_Pin|ACK_Pin|MAX2771_SHDN_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
 
  /*Configure GPIO pins : D8_Pin D9_Pin D2_Pin D10_Pin
                           D11_Pin D0_Pin D1_Pin D12_Pin
                           D13_Pin D14_Pin D15_Pin D3_Pin
                           D4_Pin D5_Pin D6_Pin D7_Pin */
  GPIO_InitStruct.Pin = D8_Pin|D9_Pin|D2_Pin|D10_Pin
                          |D11_Pin|D0_Pin|D1_Pin|D12_Pin
                          |D13_Pin|D14_Pin|D15_Pin|D3_Pin
                          |D4_Pin|D5_Pin|D6_Pin|D7_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
  /*Configure GPIO pin : DATA_READY_Pin */
  GPIO_InitStruct.Pin = DATA_READY_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(DATA_READY_GPIO_Port, &GPIO_InitStruct);
 
  /*Configure GPIO pin : BUTTON_1_Pin */
  GPIO_InitStruct.Pin = BUTTON_1_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  HAL_GPIO_Init(BUTTON_1_GPIO_Port, &GPIO_InitStruct);
 
  /* EXTI interrupt init*/
  HAL_NVIC_SetPriority(EXTI3_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(EXTI3_IRQn);
 
  HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
 
}

Actually the values from GPIO port B are coming from different module. So, a random values are coming on GPIOB [0:15]. In each time the values are obtained, I am setting and reseting the PIN5 on GPIO port C. Therefore, the other module will be acknowledged that the data is received. I am also observing some data if I connect oscilloscope to one of the GPIO port B pin. My expectation is at least gathering a data different than all zeros.

Furthmermore, I also connected the Pin 0 of GPIO port B to Vcc. However, still I am observing zeros in transmitted data.

Remi QUINTIN
ST Employee

​I dont see port B being configured in input mode. I assume it is done somewhere.

How is declared p_data?

IDR is a 32 bit register . If you declare it as an uint16_t *, you may be pointing to the upper part of the IDR which is never updated (refer to the register manual).

Using GPIOB->IDR is going to read the whole register, only the low order bits are carrying data, and the only thing stored to the array,

Perhaps read into a temporary variable, and breakpoint if zero, if this is not a value expected to be seen.

>>In order to expalin it clearer, I am sharing my implementations as well...

Sorry this selective cut-n-paste style lacks clarity and more specifically completeness.

Not clear what pins are what, which is causing the EXTI here.

Some variables are missing, others need to be volatile.

Make sure the EXTI doesn't yield into other tasks. Perhaps toggle a GPIO so you can confirm an edge trigger to service interval.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

First of all thank you guys for your answers and help. Sorry for if I am not explaining clearer. I will take care of this and I am trying to give clearer answers as far as I can.

>> I dont see port B being configured in input mode. I assume it is done somewhere.

In line 33 of the MX_GPIO_Init() function, I was setting the GPIOB as input. Am I doing something wrong there? This is also auto-generated by STM32-CubeMx after configuration of the pins.

>> How is declared p_data?

I declared the p_data as uint16_t *p_data;

>> DR is a 32 bit register . If you declare it as an uint16_t *, you may be pointing to the upper part of the IDR which is never updated (refer to the register manual).

I am also aware of that IDR is 32 bit register and I also tried by typecasting with (uint16_t)GPIOB->IDR and assigned it to the p_data. However, I am still observing zeros.

I wanted to prevent the confusion by posting the whole code but for the sake of completeness here is my whole complete GPIO initialization function;

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
 
  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOE_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();
 
  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOC, START_Pin|ACK_Pin|MAX2771_SHDN_Pin, GPIO_PIN_RESET);
 
  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, SLEEP_EN_Pin|MAX2771_CS_Pin, GPIO_PIN_RESET);
 
  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(PE4_GPIO_Port, PE4_Pin, GPIO_PIN_RESET);
 
  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOD, PD0_Pin|PD1_Pin, GPIO_PIN_RESET);
 
  /*Configure GPIO pins : START_Pin ACK_Pin MAX2771_SHDN_Pin */
  GPIO_InitStruct.Pin = START_Pin|ACK_Pin|MAX2771_SHDN_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
 
  /*Configure GPIO pins : D8_Pin D9_Pin D2_Pin D10_Pin
                           D11_Pin D0_Pin D1_Pin D12_Pin
                           D13_Pin D14_Pin D15_Pin D3_Pin
                           D4_Pin D5_Pin D6_Pin D7_Pin */
  GPIO_InitStruct.Pin = D8_Pin|D9_Pin|D2_Pin|D10_Pin
                          |D11_Pin|D0_Pin|D1_Pin|D12_Pin
                          |D13_Pin|D14_Pin|D15_Pin|D3_Pin
                          |D4_Pin|D5_Pin|D6_Pin|D7_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
  /*Configure GPIO pin : DATA_READY_Pin */
  GPIO_InitStruct.Pin = DATA_READY_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(DATA_READY_GPIO_Port, &GPIO_InitStruct);
 
  /*Configure GPIO pins : EXT_TRIG_Pin I2C_INT_N_RTC_Pin CONFIG_3_Pin CONFIG_2_Pin
                           CONFIG_1_Pin CONFIG_0_Pin MAX2771_LD_Pin */
  GPIO_InitStruct.Pin = EXT_TRIG_Pin|I2C_INT_N_RTC_Pin|CONFIG_3_Pin|CONFIG_2_Pin
                          |CONFIG_1_Pin|CONFIG_0_Pin|MAX2771_LD_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
  /*Configure GPIO pins : SLEEP_EN_Pin MAX2771_CS_Pin */
  GPIO_InitStruct.Pin = SLEEP_EN_Pin|MAX2771_CS_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
  /*Configure GPIO pin : BUTTON_1_Pin */
  GPIO_InitStruct.Pin = BUTTON_1_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  HAL_GPIO_Init(BUTTON_1_GPIO_Port, &GPIO_InitStruct);
 
  /*Configure GPIO pin : PE4_Pin */
  GPIO_InitStruct.Pin = PE4_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(PE4_GPIO_Port, &GPIO_InitStruct);
 
  /*Configure GPIO pins : PD0_Pin PD1_Pin */
  GPIO_InitStruct.Pin = PD0_Pin|PD1_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
 
  /* EXTI interrupt init*/
  HAL_NVIC_SetPriority(EXTI3_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(EXTI3_IRQn);
 
  HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
 
}

I have one push button (PA8) and one GPIO pin (PC3) that create interrupts.

>> Make sure the EXTI doesn't yield into other tasks. Perhaps toggle a GPIO so you can confirm an edge trigger to service interval.

I also tested this and I can observe that interrupt handler seems to work as expected.

Previously my implementation was working with the STM32Cube_FW_WB V1.1.0, however I was not able to send more than 20bytes at a time. I upgraded the firmware to V1.8.0 and used DataThroughput Example in order to increase the MTU size 200bytes. I didn't change anything in GPIO initialization and interrupt handler. I can get 200bytes at a time but the data is all zeros. This is what I don't understand.

Remi QUINTIN
ST Employee

​Just try to do it the other way. Read the IDR register as a full 32 bit value using a temporary 32-bit variable and check whether the value is stil 0.

If not, the cast is not working properly.

I am checking whether this register is 0 or not and setting one GPIO pin to 1 if this register is not zero. If it is zero then I am setting this GPIO pin 0. At the same time I am checking one of the pin of GPIOB with an oscilloscope. I am seeing that there is data on GPIOB pin. However, the pin that I am using for checking the GPIOB->IDR is all the time 0. I thought maybe there is an hardware problem on the board and try with the different board but the result is the same.

Remi QUINTIN
ST Employee

Set a break point in your handler to confirm the interrupt is properly serviced (assuming the handler is correctly set as the callback of this interrupt)

Last resort use another GPIO port if can consider that GPIO port B may be having a HW issue.