5 years, 10 months ago.

ST32L476RG and I2C Transfer support

Does the ST STM32L476RG have support in the mbed OS for I2C.transfer(...)? It is in the documentation and can compile, but the peripheral pins are not affected and the callback is never called. A simple read/write works.

Sorry! Below should be the properly formatted code. Also, compiling the with Keil ARMCC latest update of mbed OS as a .lib, using "startup_stm32l476xx.s"

#include "mbed.h"

/* I2C */
#define SDA1  PB_7	/*<< */
#define SCL1  PB_6	/*<< */ 
#define PERIPHERAL_BUSY		-1
#define TRANSFER_STARTED	0
#define I2C_RETRY_DELAY_MS  1
I2C i2c1( SDA1 , SCL1 );

/* MLX90614 */
#define mlx90614_i2c 					i2c1 
#define MLX90614_TA_RAM_ADDRESS			0x06
#define MLX90614_TOBJ1_RAM_ADDRESS		0x07
#define MLX90614_I2C_ADDRESS 			0xB4		// 8-bit adressing
#define mlx90614_conversion( x )	 	((((((x[1]&0x007f)<<8)+x[0])*0.02)-0.01)-273 ) // see data sheet for counts to degrees C conversion values
 
  		
static bool mlx90614_i2c_busy;
 
void mlx90614_i2c_callback( int argument ){
	mlx90614_i2c_busy = false;
}  
void mlx90614_i2c_transfer( const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length ){
	
	
	while( mlx90614_i2c_busy ) {};
	mlx90614_i2c_busy = true;	
 	while( TRANSFER_STARTED != mlx90614_i2c.transfer( 	MLX90614_I2C_ADDRESS, 
														tx_buffer, tx_length, 
														rx_buffer, rx_length, 
														mlx90614_i2c_callback, 
														I2C_EVENT_TRANSFER_COMPLETE, 
														false 
													 ) ) { wait_ms( I2C_RETRY_DELAY_MS ); };
	while( mlx90614_i2c_busy ) {};
}
void mlx90614_init( void ){
	mlx90614_i2c_busy = false;	
}
float get_Temperature( int address ){
	char tx[1],rx[3];
	float temperature;
	
	tx[0] = address; 							
	mlx90614_i2c_transfer( tx, 1, rx, 3 );		
	temperature = mlx90614_conversion( rx );	
	return temperature;
}
float mlx90614_getTemperatureAmbient( void ){
	return get_Temperature( MLX90614_TA_RAM_ADDRESS );
}

int main( void ){
	
	mlx90614_init();
	
	while( true ){
		float f = mlx90614_getTemperatureAmbient();
		wait( 0.5 );
	}
	
}
posted by Stephen Davis 19 Jun 2018

mbed_config.h

#ifndef __MBED_CONFIG_DATA__
#define __MBED_CONFIG_DATA__

// Configuration parameters
#define MBED_CONF_LORA_DEVICE_ADDRESS 0x00000000
#define MBED_CONF_LORA_PUBLIC_NETWORK 1 
#define NVSTORE_ENABLED 1
#define MBED_CONF_LORA_DEVICE_EUI {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
#define MBED_CONF_EVENTS_SHARED_DISPATCH_FROM_APPLICATION 0 // library:events
#define MBED_CONF_PPP_CELL_IFACE_APN_LOOKUP 1 // library:ppp-cell-iface
#define MBED_CONF_EVENTS_PRESENT 1 // library:events
#define MBED_CONF_LORA_NB_TRIALS 12 // library:lora
#define MBED_LFS_INTRINSICS 1 // library:littlefs
#define MBED_LFS_PROG_SIZE 64 // library:littlefs
#define MBED_CONF_LORA_PHY 0 // library:lora
#define MBED_CONF_PLATFORM_FORCE_NON_COPYABLE_ERROR 0 // library:platform
#define MBED_CONF_TARGET_LOWPOWERTIMER_LPTIM 1 // target:NUCLEO_L476RG
#define MBED_CONF_DRIVERS_UART_SERIAL_RXBUF_SIZE 256 // library:drivers
#define MBED_LFS_LOOKAHEAD 512 // library:littlefs
#define NVSTORE_MAX_KEYS 16 // library:nvstore
#define MBED_CONF_NSAPI_PRESENT 1 // library:nsapi
#define MBED_CONF_FILESYSTEM_PRESENT 1 // library:filesystem
#define MBED_CONF_PPP_CELL_IFACE_BAUD_RATE 115200 // library:ppp-cell-iface
#define MBED_LFS_BLOCK_SIZE 512 // library:littlefs
#define MBED_CONF_PPP_CELL_IFACE_AT_PARSER_BUFFER_SIZE 256 
#define MBED_CONF_PLATFORM_STDIO_FLUSH_AT_EXIT 1 
#define MBED_LFS_READ_SIZE 64 // library:littlefs
#define MBED_CONF_PLATFORM_STDIO_BAUD_RATE 9600 // library:platform
#define CLOCK_SOURCE USE_PLL_MSI // target:NUCLEO_L476RG
#define MBED_CONF_PLATFORM_STDIO_BUFFERED_SERIAL 0 // library:platform
#define MBED_CONF_LORA_NWKSKEY {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // library:lora
#define MBED_CONF_EVENTS_SHARED_HIGHPRIO_STACKSIZE 1024 // library:events
#define MBED_CONF_LORA_DUTY_CYCLE_ON 1 // library:lora
#define MBED_CONF_LORA_ADR_ON 1 // library:lora
#define MBED_CONF_LORA_LBT_ON 0 // library:lora
#define MBED_CONF_LORA_TX_MAX_SIZE 64 // library:lora
#define MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE 9600 // library:platform
#define MBED_CONF_RTOS_PRESENT 1 // library:rtos
#define MBED_CONF_EVENTS_SHARED_EVENTSIZE 256 // library:events
#define MBED_CONF_LORA_APP_PORT 15 // library:lora
#define MBED_CONF_CELLULAR_RANDOM_MAX_START_DELAY 0 // library:cellular
#define MBED_CONF_PPP_CELL_IFACE_AT_PARSER_TIMEOUT 8000 // library:ppp-cell-iface
#define MBED_CONF_LORA_APPSKEY {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // library:lora
#define MBED_CONF_LORA_APPLICATION_EUI {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 
#define MBED_CONF_DRIVERS_UART_SERIAL_TXBUF_SIZE 256 // library:drivers
#define MBED_CONF_CELLULAR_USE_APN_LOOKUP 1 // library:cellular
#define MBED_CONF_PLATFORM_STDIO_CONVERT_TTY_NEWLINES 0 
#define MBED_CONF_EVENTS_USE_LOWPOWER_TIMER_TIC

posted by Stephen Davis 20 Jun 2018

1 Answer

5 years, 10 months ago.

Hello Stephen,

I2C transfer is a function of the Mbed OS system. Therefore, it should be supported for all Mbed enable MCU. Can you post your code so that I can try to recreate the problem and maybe figure out what is wrong?

Please let me know if you have any questions!

- Peter, team Mbed

If this solved your question, please make sure to click the "Thanks" link below!

Accepted Answer

Thanks for the help. I've stripped down the code and posted below. I can see the first write transaction on my logic analyzer - though I am receiving a NACK on the write. However, regardless of the ACK or NACK I should be hitting my callback, but this is never reached. My code gets stuck on the flag that is never cleared in the callback. (Note: In other implementations using FreeRTOS I've use thread safe methods for this busy flag, but I'm pretty sure in this case a global variable will work. I have tried making this flag static with the same result.)

<<code>

  1. include "mbed.h"

/* I2C */

  1. define SDA1 PB_7 /*<< */
  2. define SCL1 PB_6 /*<< */
  3. define PERIPHERAL_BUSY -1
  4. define TRANSFER_STARTED 0
  5. define I2C_RETRY_DELAY_MS 1 I2C i2c1( SDA1 , SCL1 );

/* MLX90614 */

  1. define mlx90614_i2c i2c1
  2. define MLX90614_TA_RAM_ADDRESS 0x06
  3. define MLX90614_TOBJ1_RAM_ADDRESS 0x07
  4. define MLX90614_I2C_ADDRESS 0xB4 8-bit adressing
  5. define mlx90614_conversion( x ) ((((((x[1]&0x007f)<<8)+x[0])*0.02)-0.01)-273 ) see data sheet for counts to degrees C conversion values

bool mlx90614_i2c_busy;

void mlx90614_i2c_callback( int argument ){ mlx90614_i2c_busy = false; } void mlx90614_i2c_transfer( const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length ){

while( mlx90614_i2c_busy ) {}; mlx90614_i2c_busy = true; while( TRANSFER_STARTED != mlx90614_i2c.transfer( MLX90614_I2C_ADDRESS, tx_buffer, tx_length, rx_buffer, rx_length, mlx90614_i2c_callback, I2C_EVENT_TRANSFER_COMPLETE, false ) ) { wait_ms( I2C_RETRY_DELAY_MS ); }; while( mlx90614_i2c_busy ) {}; } void mlx90614_init( void ){ mlx90614_i2c_busy = false; } float get_Temperature( int address ){ char tx[1],rx[3]; float temperature;

tx[0] = address; mlx90614_i2c_transfer( tx, 1, rx, 3 ); temperature = mlx90614_conversion( rx ); return temperature; } float mlx90614_getTemperatureAmbient( void ){ return get_Temperature( MLX90614_TA_RAM_ADDRESS ); }

int main( void ){

mlx90614_init();

while( true ){ float f = mlx90614_getTemperatureAmbient(); wait( 0.5 ); }

}

<</code>

posted by Stephen Davis 19 Jun 2018

Updated comment above. Also, I'm finding that any call to wait(...) gets hungup in "mbed_wait_api_rtos.cpp" on line 48. It seems that the call to ricker_read(ticker) on line 38 always returns 0. I'm not sure why these timers never get started. Thanks!

posted by Stephen Davis 19 Jun 2018

Hi Stephen, I had looked at your code and tested it using a similar sensor. It is seem to be working on my board. How are you debugging it? Can you try putting a break point mlx90614_i2c_callback function and run the code to see if the that function was ever call after the transfer function is complete?

- Peter, team Mbed

posted by Peter Nguyen 20 Jun 2018

Peter, thanks again.

I'm using a Nucleo board and the St-Link Debugger through Keil. I've set a breakpoint at that callback, but it never gets hit. Any time I call any variation of wait(...) I get hung up as well. I set up the project by doing a copy/paste of a project created with the CLI specific to this IDE and target. It seems like I may be missing something in my setup file. I've added it below. It's a little silly that this is getting hung up. It's a pretty straightforward function. I have that feeling it's something simple that I'm overlooking.

Note: looks like I'm character limited in a response. I'll post the file in the original question above.

posted by Stephen Davis 20 Jun 2018

Hi Stephen, Can you try exporting the project to Keil instead of copy/paste? You might have missed config when you just copy/paste the code. If you go to your Online Mbed Compiler and click on your project folder, on the very right hand column which called Project Details, there should be an Export button. Click on that and it should open up another window that allowed you to choose your IDE export config. /media/uploads/petern98/screen_shot_2018-06-20_at_12.49.39_pm.png /media/uploads/petern98/screen_shot_2018-06-20_at_12.49.52_pm.png

posted by Peter Nguyen 20 Jun 2018

@Peter

I just copied all that code into the online compiler, built and loaded the file and it is working. I exported that to my IDE and debugged the program. It is working and hitting a breakpoint in the callback. There has to be something wrong with the configuration of my original project, but I'm not sure what it is. Any suggestions on where to look?

Thanks, Stephen

posted by Stephen Davis 20 Jun 2018

@Peter Sorry, when I said "copy/paste", I do that from Windows explorer. I start with a starter project that I have setup the way I like it, then copy that and customize it into a new project. I do this because rather than use the mbed library within my project, I place it one directory above, create an mbed.lib and then all my projects share the same mbed library (much more lightweight in storage and compilation time). The pain is setting up the project's include directories each time. That's why I use a template project. I also have to use the correct target's startup file.

Is there an issue with setting up a project this way? I've done this with other APIs, but I know that the online compiler and the CLI's export function sets up a project specific to my target and IDE. Am I missing something with my method?

posted by Stephen Davis 20 Jun 2018

Hi Stephen,

It seems that your problem is how to compile a static Mbed OS library for all your project. The instruction on how to do that is here: https://github.com/ARMmbed/mbed-cli#compiling-static-libraries

If you run into any problem then you can reference these previous post:

  1. https://os.mbed.com/questions/76149/linking-mbed-libs-in-one-directory-to-mu/
  2. https://os.mbed.com/questions/77558/How-to-generate-mbed-os-static-library-a/
  3. https://os.mbed.com/forum/mbed/topic/28056/?page=1#comment-53941

Please let me know if you have any questions!

- Peter, team Mbed

If this solved your question, please make sure to click the "Thanks" link below!

posted by Peter Nguyen 20 Jun 2018

@Peter

Thanks for that information on compiling static libraries. It seems that this may be where my issue lies - once I move to a static library the breakpoint in the callback never get hit. Will you please try to replicate my setup and see if you have insight as to what the problem might be? I'll detail it below:

1) Copy main.cpp from above in the online compiler, compile and load onto device to confirm code is valid (STM32L476RG). 2) Export project into Keil uVision5, compile, set breakpoint in callback, debug and confirm breakpoint is hit. 3) In Keil's project options -> Ouput, select Create Library to generate a .lib file containing mbed-os library local to project (may choose to first remove main.cpp from project then replace after compilation). 4) Remove "mbed-os" group from project. 5) Add a new group to the project and add the newly created .lib and the correct startup file (startup_stm32l476xx.s) found in the local mbed-os directory. 6) Compile (don't forget to change project options -> Output back to Create Executable) to confirm compilation and linking are valid. 7) Debug project and see if breakpoint during callback is hit.

This should produce a project that is using the same content as before, only in a .lib rather than the source files. But when I follow this procedure my code will run, but has an issue with the callback. With this setup I am not using a localized library, I am just converted the one imported from the online compiler to a static library. It's possible there is an issue with how Keil generates the static lib and I'll follow the link you sent above to see if that changes anything.

On an interesting note, I have been using centralized static libraries for this same project and am using a SPI callback without any issue. It was only when I added I2C operations and used the I2C callback that I ran into the issue.

Thanks, Stephen

posted by Stephen Davis 21 Jun 2018

Hi Stephen,

I had talked to our MBed developers and they said it is not possible to create a static Mbed OS library. This is because inside Mbed OS library, there are weak-symbolic link that allowed the Mbed OS to overwrite C standard library function like malloc and dealloc. This is to make these functions thread safe, a requirement in an RTOS system. Therefore, without the weak-symbolic link, the transfer function might possible be using the standard C library and running into a race condition somewhere. Mbed OS 2 used to support static library but Mbed OS 2 is not a RTOS system. That why, Mbed OS 5 required you to have a Mbed OS folder inside each of your project.

Peter, team Mbed

posted by Peter Nguyen 21 Jun 2018

@Peter

Okay, that's consistent with other tests I've been running trying to figure this out. Thanks for all your help. I'll mark this as answered.

posted by Stephen Davis 21 Jun 2018