{"id":8818,"date":"2024-04-03T11:48:08","date_gmt":"2024-04-03T18:48:08","guid":{"rendered":"https:\/\/visualgdb.com\/w\/?p=8818"},"modified":"2024-04-03T11:48:08","modified_gmt":"2024-04-03T18:48:08","slug":"recording-nrfconnect-gatt-operations-with-software-tracing","status":"publish","type":"post","link":"https:\/\/visualgdb.com\/tutorials\/tracing\/embedded\/nrfconnect\/","title":{"rendered":"Recording NRFConnect GATT operations with Software Tracing"},"content":{"rendered":"<p>This tutorial shows how to use the <a href=\"https:\/\/visualgdb.com\/documentation\/tracing\/\">Software Tracing feature<\/a> to record the Bluetooth LE attribute reads\/writes processed by the nRFConnect SDK.<\/p>\n<p>Due to the way the NRF52 chip works, stopping it on a classical breakpoint would make it stop handling the Bluetooth LE packets and would ultimately trigger a watchdog reset. Software Tracing on the other hand, is not affected by it: tracepoints run directly on the target with minimal overhead, store the captured data in a circular memory buffer, and let the NRF52 hardware continue working while the debugger is reading out and analyzing the stored trace events.<\/p>\n<p>We will create a basic project using the Nordic LED and Button Service (LBS), will use the nRFConnect App to write the LED attribute and read the button attribute, and will then configure tracepoints to record these events without interrupting the program.<\/p>\n<p>Before you begin, install VisualGDB 6.0 or later.<\/p>\n<ol>\n<li>Start Visual Studio and open the VisualGDB nRFConnect Project Wizard:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/01-prjwiz.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8819\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/01-prjwiz.png\" alt=\"\" width=\"1014\" height=\"675\" \/><\/a><\/li>\n<li>Enter the name and location for your project:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/02-prjname-2.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8820\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/02-prjname-2.png\" alt=\"\" width=\"1014\" height=\"675\" \/><\/a><\/li>\n<li>Proceed with creating a new project based on one of the SDK samples: <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/03-newprj.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8821\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/03-newprj.png\" alt=\"\" width=\"856\" height=\"693\" \/><\/a><\/li>\n<li>Select the latest ARM toolchain, install the nRFConnect SDK if you have not done it already, and pick your board in the target list: <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/04-device.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8822\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/04-device.png\" alt=\"\" width=\"856\" height=\"693\" \/><\/a><\/li>\n<li>Locate and select the <strong>peripheral_lbs<\/strong> example:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/05-lbs.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8823\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/05-lbs.png\" alt=\"\" width=\"856\" height=\"693\" \/><\/a><\/li>\n<li>Finally, connect your board to the USB port and let VisualGDB detect the debugger configuration:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/06-debug.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8824\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/06-debug.png\" alt=\"\" width=\"856\" height=\"693\" \/><\/a><\/li>\n<li>Press&#8221;Finish&#8221; to create the project. Once it is created, locate the callback function for the LED attribute (<strong>app_led_cb<\/strong>) and set a regular breakpoint in it:<br \/>\n<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/07-led.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8825\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/07-led.png\" alt=\"\" width=\"1231\" height=\"800\" \/><\/a>Note that the breakpoint <strong>will<\/strong> disrupt the program flow, so we only use it to find the place where to put a non-disruptive tracepoint.<\/li>\n<li>Build and run the project. Then, open the nRFConnect app on your phone, locate the board there and try writing the LED attribute:\u00a0 <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/08-app.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8826\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/08-app.png\" alt=\"\" width=\"1440\" height=\"2960\" \/><\/a><\/li>\n<li>The breakpoint will trigger. Use the Call Stack window to see how the callback was invoked by the <strong>write_cb()<\/strong> function in <strong>attr.c<\/strong>:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/09-write_cb.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8827\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/09-write_cb.png\" alt=\"\" width=\"1231\" height=\"800\" \/><\/a>The line calling <strong>attr-&gt;write()<\/strong> is a perfect place to put a tracepoint recording all attribute writes.<\/li>\n<li>Open VisualGDB Project Properties and go to the Software Tracing page. Ensure it is switched to the <strong>Advanced view<\/strong> and check the &#8220;do not attempt to patch any code once debugging has started&#8221; checkbox:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/11-noover.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8829\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/11-noover.png\" alt=\"\" width=\"1188\" height=\"597\" \/><\/a>This allows enabling, disabling and editing the tracepoints without stopping the target (and causing a watchdog reset).<\/li>\n<li>Click to the left from line calling <strong>attr-&gt;write()<\/strong> to create a new tracepoint. Then, configure it to trace <strong>data-&gt;value<\/strong> as a dynamic array and drag <strong>len<\/strong> into the &#8220;number of elements&#8221; field:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/12-write.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8830\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/12-write.png\" alt=\"\" width=\"1231\" height=\"800\" \/><\/a><\/li>\n<li>If you set another breakpoint in the function reading the button value (<strong>app_button_cb()<\/strong>), you can see how it&#8217;s called by <strong>read_button()<\/strong> and then the value returned by it is passed to <strong>bt_gatt_attr_read()<\/strong>:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/13-read.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8831\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/13-read.png\" alt=\"\" width=\"1231\" height=\"791\" \/><\/a><\/li>\n<li>Add another tracepoint in <strong>bt_gatt_attr_read()<\/strong>. Configure it to trace <strong>attr-&gt;pointer value<\/strong> as a <strong>symbol<\/strong>:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/14-read-sym.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8832\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/14-read-sym.png\" alt=\"\" width=\"1231\" height=\"794\" \/><\/a><\/li>\n<li>Also enable tracing of <strong>value<\/strong> as a dynamic array of <strong>value_len<\/strong> elements:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/15-read-val.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8833\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/15-read-val.png\" alt=\"\" width=\"1231\" height=\"794\" \/><\/a><\/li>\n<li>Now you can remove the breakpoints and start another debug session. Every attribute read or written by the program will now generate an event in the <strong>Tracepoints<\/strong> window. You can walk through the events to see the captured data (attribute, data length, and the actual payload): <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/16-eventlist.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8834\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/16-eventlist.png\" alt=\"\" width=\"1231\" height=\"794\" \/><\/a>Capturing the address of <strong>attr<\/strong> and matching it to the offset inside the definition of the LBS service is faster than recording the GUID of each attribute. The variable addresses may change from version to version, however the offset of each attribute within <strong>attr_lbs_svc<\/strong> will remain constant, as long as its layout remains the same.<\/li>\n<li>Create a new table view from the popup menu in the Trace Data window:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/17-table.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8835\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/17-table.png\" alt=\"\" width=\"1231\" height=\"794\" \/><\/a><\/li>\n<li>Drag the <strong>attr<\/strong> and <strong>value[0]<\/strong> into separate columns: <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/18-attr.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8836\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/18-attr.png\" alt=\"\" width=\"1231\" height=\"794\" \/><\/a><\/li>\n<li>VisualGDB will show a table view summarizing the recorded read and write operations:<br \/>\n<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/19-table.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8837\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/19-table.png\" alt=\"\" width=\"1231\" height=\"794\" \/><\/a>In this example, we wrote 0, then 1 into the LED, and then queried the button state 4 times, out of which the last one returned 1.<\/li>\n<li>Although setting new tracepoints requires patching the code (and hence triggering the watchdog), you can enable\/disable existing tracepoints, or change what they record, in a completely non-intrusive way. In order to do that, call the <strong>ARM_MPU_Disable()<\/strong> function from <strong>main()<\/strong> or change the MPU configuration to explicitly allow running code from RAM:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/20-mpu.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8838\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/20-mpu.png\" alt=\"\" width=\"1231\" height=\"794\" \/><\/a><\/li>\n<li>Create a new tracepoint folder called &#8220;GATT R\/W&#8221; and move the tracepoints there. Now you can enable\/disable them both by right-clicking on the folder and selecting &#8220;Disable selected tracepoints&#8221;:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/21-disable.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8839\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/21-disable.png\" alt=\"\" width=\"1231\" height=\"794\" \/><\/a><\/li>\n<li>Try changing the write() tracepoint to record <strong>user_data<\/strong>:<br \/>\n<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/22-edit.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8840\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/22-edit.png\" alt=\"\" width=\"1231\" height=\"794\" \/><\/a><\/li>\n<li>Once you click &#8220;Commit&#8221;, VisualGDB will update the tracing program accordingly and redirect the old tracepoint to use it:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/23-newdata.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8841\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/23-newdata.png\" alt=\"\" width=\"1231\" height=\"794\" \/><\/a><\/li>\n<li>Press Shift-F5 to stop debugging. VisualGDB will create trace report file containing all recorded data. You can use it later to step through the recorded events, view tables\/graphs, or export everything into a machine-readable XML file:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/24-report.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8842\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/24-report.png\" alt=\"\" width=\"1231\" height=\"794\" \/><\/a><\/li>\n<li>If you want to record the GATT requests at any time in the future, simply leave the tracepoints inserted but disabled. This will add a minor runtime overhead, but won&#8217;t trigger the watchdog when you enable them. Alternatively, you can export them to a tracepoint set and remove them from the list: <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/25-export.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8843\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2024\/03\/25-export.png\" alt=\"\" width=\"1231\" height=\"794\" \/><\/a>This will eliminate any overhead, and next time you need them, you can simply import the tracepoint set without having to re-create and re-configure them manually.<\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>This tutorial shows how to use the Software Tracing feature to record the Bluetooth LE attribute reads\/writes processed by the<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[247],"tags":[248,204,211],"_links":{"self":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts\/8818"}],"collection":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/comments?post=8818"}],"version-history":[{"count":1,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts\/8818\/revisions"}],"predecessor-version":[{"id":8844,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts\/8818\/revisions\/8844"}],"wp:attachment":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/media?parent=8818"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/categories?post=8818"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/tags?post=8818"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}