Skip to main content

Peripheral initialization

DA1469x

11 months ago

Posted by apdobaj 65 points 16 replies
0 upvotes

I need to connect an external sensor to the DA14695 WiRa USB development kit via I2C. The driver looks fairly straightforward but I have a question about initializing the interface. The code uses an assembler directive to create a list of init functions to call (bus_init_section) but how do I add the initialization of the I2C bus to this list? As a more general question, what is the methodology for adding peripheral support using this mechanism?

11 months ago

PM_Dialog

Hi apdobaj

Generally, we strongly recommend the usage of the adapters for accessing hardware peripherals because not only provide access to the peripheral, but also make sure that other tasks which are currently accessing it, suspend their operation until the peripheral is once again released. So you don't have to worry if another task tries accessing the same peripheral at the same time. Also, in sleep mode all the peripheral blocks are powered down.

If I understood correctly, you question is how to initialize the I2C peripheral block. Please take a look at the DA1469x Tutorial I2C Adapter Concepts from the support portal.  You will find all the appropriate steps toi initialize and use the I2C adapter.

Hope this helps! In case I misunderstood your question, please clarify it.

Thanks, PM_Dialog

9 months ago

I'm still having issues trying to get this i2c driver to work. The driver is re-registering the interface because it thinks the tx fifo has data in it. I placed some test code to disable the re-register and clear the fifo but now the code hangs at the call to OS_EVENT_WAIT in ad_i2c_write. The attached code should tell you everything you need to figure this out. Start with the i2c_init method in main.c. All changes are commented with the key word apdobaj.

Attachment Size
code_apdobaj.zip 13.94 KB

9 months ago

PM_Dialog

Hi apdobaj,

I take a look at the main.c file and all the I2C transactions are implemented in i2c_init() which is called in the system_init().

The system_init() task is a highest priority task which should contain  only the calls for initializing the system and the application. It should have what is the defaults in a typical project, it should create/initialize the resources (e.g. Mutexes, timers, structures), create the initial task(s) of the application.

The system_init() task must not be used for implementing the state machine of the application or any functionality in general such as I2C transactions. Regarding the I2C, a new task should be created in the system_init() with normal priority to run the application state machine and perform I2C transactions.

In my previous  response, I had suggested to take a look at the DA1469x Tutorial I2C Adapter Concepts so that you can understand how to use the I2C adapters.

As you can see in the tutorial, the system_init() creates the prvI2CTask_EEPROM() task where I2C adapter initialization should be done once at the beginning (ad_i2c_init). This task also executes the eeprom_data_writer() to open the adapter (ad_i2c_open()) and perform some I2C write transactions (ad_i2c_write()). When the I2C activity has been finished, then the adapter should be closed (ad_i2c_close()). I would recommend first checking the suggested tutorial and implement the same functionality in your own project.

Thanks, PM_Dialog

9 months ago

OK, I followed the tutorial and now am getting a bus fault when it tries to initialize the LCD. Please advise.

Attachment Size
ble_peripheral_task.zip 15.74 KB

9 months ago

PM_Dialog

Hi apdodaj,

Can you please attach a screenshot with the error that you are getting? Is it SDK10.10?

Thanks, PM_Dialog

9 months ago

I am using the WiRa SDK 10.440.8.6. I've followed the pc and lr to determine that the calling routine address is 0xffffffbc, which I don't understand. When I attempt to single step to the fault it moves, in other words, the fault first occurs in the lcd draw routine and when I single step through that routine it works and the fault occurs further down the source code, so it doesn't appear to be related to any particular instruction. I've also reverted to the original example code and the fault still occurs. Screenshot and code attached.

Attachment Size
ble_range_dte_new.zip 14.88 KB
Screenshot 2021-03-01 095213.png 362.99 KB

9 months ago

It appears the system_init task never runs (circled breakpoint is never reached). Why would that be?

Attachment Size
Screenshot 2021-03-01 213501.png 732.2 KB

9 months ago

I am now having a different issue, the previous one was that the ble dte task was preempting the i2c task at the same priority. disconnecting the receiver allowed the i2c task to run.

Now I'm having the issue that the code gets trapped in this subroutine in port.c:

static void prvTaskExitError( void )
{
    /* A function that implements a task must not exit or attempt to return to
    its caller as there is nothing to return to.  If a task wants to exit it
    should instead call vTaskDelete( NULL ).

    Artificially force an assert() to be triggered if configASSERT() is
    defined, then stop here so application writers can catch the error. */
    configASSERT( uxCriticalNesting == ~0UL );
    portDISABLE_INTERRUPTS();
    for( ;; );
}

my task is not returning because it is implemented with the for(;;). code attached, please advise

Attachment Size
platform_devices.zip 14.39 KB

9 months ago

PM_Dialog

Hi apdodaj,

Can you please step in to the code and check when prvTaskExitError() occurs? When using the I2C task? 

Apologies but I am little bit confused with all these file. So, it would be very helpful to indicate what you are trying to implement. 

I can understand that you are using the WiRa and you would like to add I2C functionality, but what are the requirements? Could share high-level description of this application? 

If you disable the I2C, can you check fi everything is working as expected? 

Why don't you try to interact with the I2C in the ble_peripheral_task? 

Thanks, PM_Dialog

9 months ago

Here is what I'm trying to implement, this is a great question and I appreciate you trying to get a sense of the architecture. Our application is a novel type of gesture recognition that meets the particular requirements of outdoor enthusiasts, the military, nurses and other verticals that need to interact with smartphones (and other electronics) without removing protective gear or remembering complex inertial gestures that also have the problem of false positives when the user is active. We have an MVP working with the Nordic devices but pivoted to Dialog to take advantage of the wireless ranging capability that gives us the additional capability of contact tracking and collision detection in the same device. So, in summary we want to monitor the ranging application as well as the sensor and send the results of the gesture recognition and proximity to the smartphone where the user can use the gestures for command and control and be informed of collisions and social distance intrusion. There is another module in the larger system architecture that needs to send data between it and the mobile phone that is described in the attached file and we would like to use only one vendor for BTLE.

As far as the implementation, I was advised in this thread to use the task structure of FreeRTOS to take advantage of all the benefits of an RTOS and additionally to keep the timing of the gesture recognition task independent of the WiRa task. I have been able to compile and run the supplied ble_range_dte example without issue. When following the link register I have not been able to trace back far enough to determine what causes the prvTaskExitError to run, but since I don't get this with the example app I presume it's the I2C functionality. 

As general comments, I've found the build system to be extremely fragile, and have had to start from scratch numerous times to get back to a working build. And here it has been several weeks on this and I still do not have the I2C interface working, something that should be very simple implementation, like with Nordic. Our EAU is in the tens of thousands and I would like to propose a live session to get me through this after feedback on this message and I'm able to try the suggested implementation. Looking forward I'll need to implement a custom service to get the information to the mobile phone, and in the short term would like to implement the telemetry to the phone by emulating a HID device (keyboard) so that I can test without the mobile app, which is being developed by another team. So here's what I need:

1) get the I2C interface with the sensor working

2) send the sensor and proximity incursion to the mobile phone by emulating a HID keyboard keypress

3) implement a custom service with more control over the sent packets. 

Attachment Size
gestr-OnePagerFeb2021.pdf 227.04 KB

8 months ago

I've continued to work on this waiting for your answer. I've tried a large number of different combinations of synch and asynch transactions and no matter what I do nothing ever shows up in the receive register. All I'm trying to do is read the ID register of the memsic sensor device (datasheet attached). It is unclear from the API documentation what parts of the transaction are the responsibility of the implementation and which are handled by the API. For example, when reading a register from the I2C slave device using ad_write_read, does the transmit buffer need to contain the bus address of the device, or is that handled by the API? Same question with the read/write bit. Is the following code correct? The read causes an i2c_error_code of HW_I2C_ABORT_7B_ADDR_NO_ACK.

extern void i2c_read_reg( uint8_t *rxBuff , uint8_t regAddr)
{
        /*
         * Error code returned after an I2C operation. It can be used
         * to identify the reason of a failure.
         */
        __RETAINED static HW_I2C_ABORT_SOURCE i2c_error_code;

        uint8_t txBuff[] = {regAddr};

        ad_i2c_handle_t handle = ad_i2c_open(MEMSIC_5893);
        //write the register address
        i2c_error_code = ad_i2c_write( handle, txBuff, sizeof(txBuff), HW_I2C_F_ADD_RESTART );
        if (i2c_error_code != HW_I2C_ABORT_NONE) {
                printf("i2c error is %d\r\n", i2c_error_code);
        }
        ad_i2c_wait_while_master_busy(handle);
        i2c_error_code = ad_i2c_read( handle, rxBuff, 1, HW_I2C_F_ADD_STOP );
       if (i2c_error_code != HW_I2C_ABORT_NONE) {
                printf("i2c error is %d\r\n", i2c_error_code);
        }
        ad_i2c_wait_while_master_busy(handle);
        ad_i2c_close(handle, false);
        return;
}
 

Attachment Size
MMC5883MA-RevC.pdf 428.99 KB

8 months ago

PM_Dialog

Hi apdodaj,

Thanks for your comments. Let me check them and I'll get back to you shortly.

Thanks, PM_Dialog

8 months ago

I'm also confused about the io settings, having an "ON" and "OFF" setting for them. Why would you want to turn the settings to the "OFF" mode, but that's exactly what the i2c tutorial (http://lpccs-docs.dialog-semiconductor.com/tutorial_da1469x_i2c_adapter…) does. All altered code attached, as before marked with "apdobaj".

Attachment Size
ble_peripheral_task.zip 22.48 KB

8 months ago

PM_Dialog

Hi apdobaj,

In general, the adapters are an intermediate layer between the Low Level Drivers (LLDs) and a user application, so you can initialize and use the peripheral interfaces in a simpler way than when using APIs from LLDs.

The application task should open the adapter (ad_i2c_open), perform the I2C transactions and then close the adapter (ad_i2c_close).

Please also check the DA1469x I2C request response example application SW Example.

The i2c_slave_task() :

-          Opens the I2C adapter - ad_i2c_open()

-          Start slave transmission/reception -  ad_i2c_start_slave()

-          And finally closes the adapter - ad_i2c_close

In this example you will find 2 task :

i2c_master_task : sends requests, reads responses and prints them

i2c_slave_task : reads requests, counts callbacks and sends response

Both of them have normal priority - OS_TASK_PRIORITY_NORMAL.

I have download the last attachment (ble_peripheral_task.zip) and I went through the files.

The i2c_read_reg() where all the I2C initialization and transactions happen, is in the platform_devices.c file.

It is strongly note recommend to place the application code in the platform_devices.c..

Please check the suggested example – you should create a task and place all the application code for the I2C.

In platform_devices.c file, you should only add the IO bus as well as driver configurations for the I2C device(s) used. These settings will be applied when an application task attempts to interact with the I2C.

My recommendation would be to try it in a clean SDK example, make sure that you can perform the I2C transactions you need and then implement the same in your project. Right now it is very difficult to understand what is getting wrong.

Additionally, since you are using the WiRa SDK, the GA release of WiRa is coming in June.

Thanks, PM_Dialog

8 months ago

Now I feel I'm getting the run-around. Earlier in this thread you suggested "Why don't you try to interact with the I2C in the ble_peripheral_task? ", and now you're directing me to go back to the task structure. The bottom line is that I'm successfully getting the setup code (as directed in the I2C tutorial) to run and the read code to run but for some reason the "write" generates an ACK from the device but the "read" does not. Please answer my direct questions above regarding the nature of the adapter API calls as stated above and repeated here:

All I'm trying to do is read the ID register of the memsic sensor device (datasheet attached). It is unclear from the API documentation what parts of the transaction are the responsibility of the implementation and which are handled by the API. For example, when reading a register from the I2C slave device using ad_write_read, does the transmit buffer need to contain the bus address of the device, or is that handled by the API? Same question with the read/write bit. Is the following code correct? The read causes an i2c_error_code of HW_I2C_ABORT_7B_ADDR_NO_ACK.

Please examine my code for the proper setup and handing of the various GPIO and timing settings and verify that the API calls are in accordance with the datasheet for the sensor. Why is this so difficult to get these direct answers? The application code is placed in platform_devices.c because that is where the defining structs are located and so it is cleaner in calling the read routines because all you have to pass to them is the register address and value. Why should that matter that the read code is placed in platform_devices.c? And what is this GA release to which you refer? When you refer to a "clean SDK example", to which one are you referring exactly?

8 months ago

PM_Dialog

Hi apdobaj,

Apologies for the confusion.

>>For example, when reading a register from the I2C slave device using ad_write_read, does the transmit buffer need to contain the bus address of the device, or is that handled by the API?

No – this is not needed. Please check the i2c_driver_config and .i2c.address  = MEMSIC_5893_I2C_ADDR (0x30). The .i2c.address  contains the bus address of the device. This is a part of the I2C initialization driver structure that is done by the ad_i2c_open().

Are you using an external pull-up resistor? If yes, what is the value? For the standard mode @ 100Kbps ( HW_I2C_SPEED_STANDARD), the nominal external resistor is 2.2K. Keep in mind that the chip is using an internal pull-up resistor automatically.

>>The read causes an i2c_error_code of HW_I2C_ABORT_7B_ADDR_NO_ACK.

The most probable reasons for this error might be that  :

-   The I2C sensor is configured with wrong I2Cbus address. The MEMSIC_5893_I2C_ADDR (0x30) is set correctly and according to datasheet. So, I assume there is no problem on this.

-    If you are using a pull-up resistor, it might be too high, so the transactions from 0 to 1 and vice versa are too slow.

-    The I2C sensor might be in a “zombie” state and so it is not responding to the read command.

I checked the i2c_read_reg() and it seems that the APIs are being used correctly.

Could you please probe the I2C lines and share a logic analyzer capture, so that I can understand better what might be wrong?

I meant that a new release is coming in June timeframe.

Thanks, PM_Dialog