SAME54 I2C Driver Issue Solved

If you are reading this post that means you are using ATMEL or Microchip controller. We are using ATSAME54 micro from microchip, it is ARM based cortex-M4 series controller. In our application we have around eight I2C ( Inter-integrated Circuit) slave devices connected. I2C slave devices includes, RTC, onboard temperature sensor, FRAM, LED drivers etc. Well as you know all I2C slave devices can be addressed using their addresses.

Well as most of guys does we too have downloaded sample code from and tested. We have SAME54 explained pro and we brought PCA9685 LED driver. This is simple I2C based LED driver and is easily available, its schematic and design also available from adafruit. With sample code and its default address it works like charm, meaning, in first go it starts communicating with LED driver.

Now fun part starts, after verifying this we have incorporated same design in our hardware. After we receive hardware, LED driver is not at all responding, it was not coming out of sleep mode. We have tried all the options, but no luck. Now when we are running same code on explained pro it is working. So only difference was the address. With PCA9685 module connected with explained pro as I2C master, we were using default address ie 0x40. Now when we change this address by shorting address lines, it stops working. We are getting “RXNACK” bit set on (received not acknowledged). Strange thing is if we revert back its address to default address ie 0x40 it works.

When we connected oscilloscope to SDA line we were getting data, ie address then registers.

I2C without driver change


Well after lot of googling and spending almost two weeks, we found solution, that was issue with ATMEL I2C driver source code generated from The solution is very simple once you found out the root cause :-). Yes it is bug in microchip’s I2C driver and its very unique.

I2C is very simple and we suspected hardware. Started with pull up registers for SDA and SCL lines, After trying out with various combinations of pull up registers (4K, 10K, 2.2k) we diverted our attention to I2C drivers. Yes, The culprit is – ‘i2c_m_sync_cmd_read()’ and ‘i2c_m_sync_cmd_write()’ functions from ‘hal\src\hal_i2c_m_sync.c’. The present code it is sending two bytes, but it is expected is to send three bytes. We have modified these read/write commands and it is working. Please note this change is necessary if you are using I2C and code downloaded from atmel start.

Follow below steps to fix this issue,

Open – ‘hal\src\hal_i2c_m_sync.c’

In function ‘i2c_m_sync_cmd_read()’ and ‘i2c_m_sync_cmd_write()’ comment out following code, so after commenting out the functions should look as below,

	struct _i2c_m_msg msg;
int32_t           ret;
#if 0
msg.addr   = i2c->slave_addr;
msg.len    = 1;
msg.flags  = 0;
msg.buffer = ®
ret = _i2c_m_sync_transfer(&i2c->device, &msg);
if (ret != 0) {
/* error occurred */
return ret;
msg.addr   = i2c->slave_addr;
msg.flags  = I2C_M_STOP;
msg.buffer = buffer;
msg.len    = length;
ret = _i2c_m_sync_transfer(&i2c->device, &msg);
if (ret != 0) {
/* error occurred */
return ret;
return ERR_NONE;

Now connect oscilloscope and check SDA line, it gives results as expected.

I2C after change in driver

If your I2C slave devices are configured with default addresses ie 0x00, then this change is not required, but remember to make this change every time you download I2C driver code from Share your findings on I2C issues while using ATMEL SAME54P20A controller.

Modbus Master Stack On ATSAME54 With RTOS

In previous post we discussed about how to port modbus slave stack on ATSAME54. This post we will discuss on how to port modbus master stack on SAME microcontroller. You can download example freemodbus master stack for reference from FreeModbus. We have referred the ‘AT91SAM7X_FREETROS’ example project. You can follow the steps from previous post for creating directory of project files. Instead of modbus slave stack, add modbus master stack. In addition, We are using FreeRTOS in our project. So In top level directory we have added FreeRTOS V9.0.0 . Please refer to modifications in port specific files described in previous post.

So lets begin with issues while port modbus master stack on SAME, Without an operating systems there are normally no queues available. In case of modbus stack without using RTOS, the queue sending and receiving functions are implemented using a static variable which is set to TRUE when an event is posted. The receive function checks the variable and if TRUE returns the previously stored event. But in case of an RTOS the functions should use a real event queue. We Changed the function xMBPortEventPost() to post an event to a queue. This function will be called from an ISR so we have used xMBPortEventPostFromISR() API for that. This is the interrupt safe version of xMBPortEventPost() provided in FreeRTOS.

We changd the function xMBPortEventGet( ) to retrieve an event from that queue . The function should block until an event has been posted to the queue.

Like this we are calling xQueueCreateStatic() API from vQueueCreate and vQueueDelete() API from vMBPEventDelete .

Next step is to define the functions vMBPEnterCritical( ) and vMBPExitCritical( ) in file portother.c. A switch to another task cannot occur between the calls to vMBPEnterCritical and vMBPExitCritical . Only interrupts whose logical priority is above the value assigned to the configMAX_SYSCALL_INTERRUPT_PRIORITY constant can execute in critical section and interrupts are not permitted to call FreeRTOS API functions. In FreeRTOS there are API’s portENTER_CRITICAL() and portEXIT_CRITICAL() which we have used respectively in above two functions.

Note that if we are calling portENTER_CRITICAL() and portEXIT_CRITICAL() functions from ISR, the following assertion will get fail: configASSERT((portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK) == 0);

If you are also stuck here, means you are calling these APIs from ISR. In FreeRTOS there are interrupt safe APIs which can be used inside ISR. So here in this case we found following two interrupt safe versions for above functions:


Use thses APIs where the function is called from ISR:

In main function, we created two tasks using xTaskCreateStatic() API from FreeRTOS , one is application task and another is for modbus task .


We have now created the modbus master workpace. For testing it, we have to run the modbus slave program on PC side. We are developing the stack on linux system. For this system we found out the Diagslave Modbus Slave Simulator . Install it in your system then execute ‘linux_x86-64/diagslave -h’ It will show the options you can configure. We executed simulator by giving the following command:

After running modbus master program, the simulator showing this output:

Happy to help you during your port modbus master stack on SAME controllers.

Port Modbus Slave Stack On ATSAME54

We are referring modbus server stack implementation for SAM3X and We want to port it on SAME54P20A. First we have downloaded the example project for SAME54P20A which is using Usart_Asynchrnous module from Atmel START. Then create new top level directory for project files. Following files needs modification while porting, they are present in sub directory named ‘port’ which will contain all port specific files,

  • portserial.c
  • porttimer.c
  • portevent.c
  • portother.c
  • port.h

Atmel start project is having makefile in sub-directory ‘gcc’. Add these port specific files paths in makefile. Then add modbus stack folder to top level directory which is having all the modbus specific functions. For compilation we hav to add these all file paths in makefile which is in gcc directory. We have to first check the ‘port.h’ file whether it is suitable for our platform. If not ,then we have to define platform specific functions for serial interface,timer driver.

portserial.c: In this file there are functions for initializing USART, enabling and disabling USART module, enabling and disabling the receiver and transmitter. For enabling and disabling transmitter and receiver, we need to use corresponding low level API’s of ATSAME54P20A from ‘hri’ folder. The reference code for ATSAm3S:

Changes we have to do for ATSAME54:

In reference program for SAM3X they are using vUSARTHandler() interrupt handler in which they are checking for Rx or Tx interrupt invoked according to that respective xMBPortSerialGetByte(), xMBPortSerialPutByte() functions are called.

For SAME54P20A, there is an API- ‘usart_async_register_callback()’ so instead of ‘vUSARTHandler’, we have to create two different interrupt service routines one is for Rx interrupt and another for Tx interrupt.

portimer.c: The modbus protocol stack requires timer for detection of end of the frame. There are API’s available in SAME54P20A timer driver for initializing ,enabling and disabling the timer. For SAM3X they are using timer interrupt function TCX_IRQHANDLER() which is calling pxMBPortCBTimerExpired() function.

For ATSAME54P20A, there is timer task structure. So instead of using timer_handler we have to initialize timer structure which is having callback function in which we will call ‘pxMBPortCBTimerExpired()’ function.

If you are using FreeRTOS in your project then you need to modify ‘portevent.c’, We are not using rtos in our project so will not discuss on updating portevent functions. In next section we will update on it.

How To Use Two Timers In Same Project

If you are using SAM series controller you probably have came across this question, How do i implement two timer which generate two interrupt at different time in same project? or How we can use two timer in same project in SAME54 controller? Well SAM series controller are ARM-based MCUs and MPUs from ATMEL now Microchip.

We are using ATSAME54P20A ie SAME54 explained pro board to evaluate the functionality of it. So created new project using with TC0 and TC1 along with WDT and interrputs. The project tree looks as below,

This project works well and TC0 timer interrupt is working but TC1 timer interrupt is not working. Following is code for initialization and using timer.

	TIMER_1_task1.interval = 50;
TIMER_1_task1.cb       = TIMER_1_task1_cb;
TIMER_1_task1.mode     = TIMER_TASK_REPEAT;
timer_add_task(&TIMER_1, &TIMER_1_task1);
TIMER_0_task1.interval = 10;
TIMER_0_task1.cb       = TIMER_0_task1_cb;
TIMER_0_task1.mode     = TIMER_TASK_REPEAT;
timer_add_task(&TIMER_0, &TIMER_0_task1);

Put breakpoint in ‘TIMER_1_task1_cb’ function and it never hits breakpoint, but it hits breakpoint in ‘TIMER_0_task1_cb’ function. When we check out status flag of timer1, as soon as it initializes TC0 using ‘TIMER_0_init()’ from driver_init.c it sets ‘STOP’ and ‘SLAVE’ bit.

Bit 1 – SLAVE Slave Status Flag
This bit is only available in 32-bit mode on the slave TC (i.e., TC1 and/or TC3). The bit is set when the associated master TC (TC0 and TC2, respectively) is set to run in 32-bit mode.
Bit 0 – STOP Stop Status Flag
This bit is set when the TC is disabled, on a Stop command, or on an overflow/underflow condition when the One-Shot bit in the Control B Set register (CTRLBSET.ONESHOT) is ‘1’.

Problem is while using configuration there is no option to set timer in 8 bit or 16 bit or 32 bit mode. By default when we create project it sets in 32-bit mode.

Solution to this issue is set both timers in either 16-bit or 8 bit mode. The settings can be found in “Config\hpl_tc_config.h” file. The change should look like as below

#ifndef CONF_TC0_MODE
#ifndef CONF_TC1_MODE

With this change both timers are working.

How To Write RTOS Safe ISR For ATSAME

In our application it is required to use FreeRTOS API functions from an interrupt service routine(ISR). Good thing about FreeRTOS is it has provided interrupt safe API, meaning one can use FreeRTOS API functions from ISR, as they have provided two versions of some API. Functions intended for use from ISRs have “FromISR” appended to their name eg. xQueueSendFromISR

In our application we were using xQueueSendFromISR() from IRQ10 ie ‘EIC_10_IRQn’, to send message to other task, code snippet is as below

void sendMsgToIoTaskFromISR(int eventId, int data)
Task_EventMsg_t evtMsg;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;   	// wake up the higher priority task
evtMsg.eventId = eventId;
evtMsg.iData = data;    
if( xQueueSendFromISR( gIo.ioMgrQHandle, ( void * ) &evtMsg, &xHigherPriorityTaskWoken ) != pdPASS )
/* If the task with handle xTaskToNotify was blocked waiting for the notification
then sending the notification will have removed the task from the Blocked
state.  If the task left the Blocked state, and if the priority of the task
is higher than the current Running state task (the task that this interrupt
interrupted), then lHigherPriorityTaskWoken will have been set to pdTRUE
internally within vTaskNotifyGiveFromISR().  Passing pdTRUE into the
portEND_SWITCHING_ISR() macro will result in a context switch being pended to
ensure this interrupt returns directly to the unblocked, higher priority,
task.  Passing pdFALSE into portEND_SWITCHING_ISR() has no effect. */	
portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );

With this it is calling assert using function “portASSERT_IF_INTERRUPT_PRIORITY_INVALID();” when we did some digging it is failing because of the condition ‘ucCurrentPriority >= ucMaxSysCallPriority’ . The reason to fail this condition is ‘ ucCurrentPriority’ is ‘0’ and ucMaxSysCallPriority is 128 (0x80). After reading FreeRTOS documentation on how ISR priorities are set. It is understood that ISR priorities are set to ‘0’ by controller and RTOS expects the priority to be ‘128’ or above, as recommended below:

 Remember that ARM Cortex-M cores use numerically low priority numbers to represent HIGH priority interrupts. This can seem counter-intuitive and is easy to forget! If you wish to assign an interrupt a low priority do NOT assign it a priority of 0 (or other low numeric value) as this will result in the interrupt actually having the highest priority in the system – and therefore potentially make your system crash if this priority is above configMAX_SYSCALL_INTERRUPT_PRIORITY. Also, do not leave interrupt priorities unassigned, as by default they will have a priority of 0 and therefore the highest priority possible.

That is suggestion from FreeRTOS, but how to change priority of interrupts, To solve this issue we have done workaround, probably it might help someone. In ‘hpl_eic.c’ file from “hpl\eic” folder, in function “_ext_irq_init” change the priority of IRQ10 to 128 or more that that. Simply add below line

NVIC_SetPriority(EIC_10_IRQn, NVIC_SIGNAL_PRI_80);

Your new code should look like

NVIC_SetPriority(EIC_10_IRQn, NVIC_SIGNAL_PRI_80);

Compile and test this new code and you will see interrupts are working in your RTOS.

This trick of setting interrupt priority to 0x80 works well for other interrupts as well, like timer interrupt, External interrupts etc. Just make sure that in init function for that I/O you are calling NVIC_SetPriority() function… Happy RTOS safe ISRing..

Further Reading [PDF]Mastering the FreeRTOS™ Real Time Kernel

How To Use WDT On Free RTOS Running ATSAMEx

After doing some google and spending almost 4 hours on choosing right place to start WDT, we have decided to share our learning here. Well we are using ATSAME54P19/20 controller from Microchip formally Atmel. Watchdog timer – WDT works well without Free RTOS (10.0) but when WDT is enabled along with RTOS it simply does not work well.

In big while(1) embedded applications with no RTOS you can always initialize WDT after peripheral initialization and feed/touch WDT in while/main loop. In case of RTOS there are multiple tasks/threads and to be specific in case for Free RTOS when you try to enable WDT right before vTaskStartScheduler(); call it simply does not work.

Tried with following solutions – like configure WDT for 20 sec reset time. And enable WDT just before scheduler starts. WDT is not waiting till expiry it is immediately resetting. Then tried enabling WDT after scheduler has started but no luck.

So tried with the RTOS Hook functions . Every RTOS provides hook functions for user application. There are few hook functions in Free RTOS as well. First tried with Idle Hook function by setting configUSE_IDLE_HOOK to 1 within FreeRTOSConfig.h, but it seems this vApplicationIdleHook() function gets called only when there is nothing to be done by other tasks. In our application we have 4 tasks, along with timers enabled in it. This is reason the vApplicationIdleHook() function was not getting executed.

There is other hook function ie tick hook function vApplicationTickHook(), but that is getting called at every tick. Enabling WDT at every tick is not right place. So we need some hook function which will be called once after the RTOS scheduler is initialized. And vApplicationDaemonTaskStartupHook() is the right function. Initialize this hook by setting configUSE_DAEMON_TASK_STARTUP_HOOK to 1 in FreeRTOSConfig.h , put your WDT initialization and enable code here. From any other task or timer task you can feed WDT (wdt_feed(&WDT_0);).

void vApplicationDaemonTaskStartupHook(void)
#ifdef WDT_IN_USE 
uint32_t clk_rate;
uint16_t timeout_period;
clk_rate       = 1000;
timeout_period = 4096;
wdt_set_timeout_period(&WDT_0, clk_rate, timeout_period);

Happy WDT testing with RTOS on ATMEL controllers 🙂

Ceedling Unit Testing With ATSAME54

This post is continuation of previous post on how to mock local variable in ceedling, please check out previous post before continuing with this article. Another issue is having to add all the microchip files.

When CMock gets a hold of the header file it looks at all the functions defined there and generates several mock functions for each.

In one program, we are dealing with 4 pins of microcontroller. The pin numbers and its functions are defined in file ‘atmel_start_pins.h’ which is included in our project. But inside this file there are definitions for all the pins and ‘hal.gpio.h’ file is included. Inside ‘hal.gpio.h’ file, another files are included. The original atmel_start_pins.h file is like below, We need only 4 pins from this file:

The function under test is :


Instead of wasting memory we can create our own file ‘atmel_start_pins.h’ for unit testing. The file will contain The function declarations we want to mock and only the required data.

In above function INPUT_ENTER_KEY,INPUT_BACK_KEY etc are having values as follwing :

These PB_1,PB_2,PB_3,PB_4 are defined in file ‘atmel_start_pins.h’. So we can create our own ‘atmel_start_pins.h’ file which is having only requied data .The new file is like:

Now we can mock this required function and interfaces. We can just assign any numbers for PB_1,PB_2,PB_3,PB_4 . Pass these pin numbers in test cases.

we able to unit test without memory wastage.

Local Variable In Ceedling Unit Testing

Unit testing is code that calls some other code to check if it performing as expected.Ceedling is a build system specifically designed for running unit tests in c. Unity and CMock are open source tools for testing c.Ceedling has feature of automatic generation of mock.

  • Unity is a unit test framework.
  • CMock creates the fake versions of other modules.Using these fake versions we can verify whether our module is working correctly or not.
  • Ceedling include unit test framework(Unity) and Mocking framework(CMock).
  • It requires Ruby to run and it uses GCC to build each test.
  • Ceedling comes with a command line tool that can be used to generate the project.

‘Ceedling’ is open source tool used in unit testing, in our project which involves embedded system development we are using ‘ceedling’ framework. There are other unit test frameworks like google gTest but they are more suited for application software written high level languages like c++. Being embedded system software written in ‘C’ language we are using ‘Ceedling’ for our unit testing.


I was testing function for one module which is using the modbus APIs defined in modbus.c file. For ceedling unit testing I mocked low level APIs like modbus_read_registers() and modbus_write_register().

In our code we defined function int _readModbusRegister( ) and function int _writeModbusRegister() inside which mobus_read/write_registers APIs were used :

This image has an empty alt attribute; its file name is read_Modbus_func1.jpg

The function under test is:

In above function I need to test all the possible conditions for different value of ‘drvStatus’ variable. But ‘drvStatus’ is local variable. How can I mock the local variable in Ceedling?? We cannot directly mock local variable using Ceedling. So in this case if we made our mock function modbus_read_registers() return 1 then user defined function _readModbusRegister() will always return ‘regValue’ as zero. Because right now we are testing the code without using hardware. So always ‘drvStatus’ variable will become zero and code will not get execute further. And we cannot change the value of drvStatus with this conditions.

Solution :

In ‘Ceedling’ generally we have to mock API but for getting different value for local variable ‘drvStatus’ in this case we have to mock the function which is returning value to local variable, i.e. in this case we will mock ‘_readModbusRegister()’. The actual function which we need to mock is always returning the register value. So add these two user defined function declarations to a file and add this file prefixing _mock .Ceedling will automatically create the mock versions of given functions.

When we mock the function whose definition is present we have to comment that definition otherwise ceedling will throw error for ‘ found multiple definitions’. I commented the definitions for these two mocked functions. Now I can use these _readModbusRegister_ExpectAndReturn() function with any return value and can generate test case for every possible condition. Like in first test case we are returning 8 to ‘drivestatus’ .

Here in second test case we can return 16 to ‘drivestatus variable’.

Like this we can change value of local variable.

EmbSysRegView Alternative Plugin For Eclipse

If you are looking for alternate option for EmbSysRegView (embedded system register view) plugin or wondering ‘How to Add Register Details View in Eclipse” this post describes simple trick to it. The standard Eclipse registers view shows only the core registers, which is not enough in embedded system development. So, EmbSysRegView – is an open source solution for 8, 16 and 32 bit microcontroller to display special function registers (SFR) while debugging.

EmbSysRegView is a good plugin which supports GCC toolchain including GDB with Eclipse for emebedded system development, but it is not maintained and lacks support for new controllers. One can always refer to previous post we have seen how to add register details view in Eclipse for SAME54 series. However those steps can be used to add support for any other microcontrollers. This post describes about alternative to EmbSysRegView.

Eclipse provide peripherals view, this view shows details based on memory location meaning, you can monitor memory locations using this view. By default this view looks like as shown in this screenshot.

Peripherals view in Eclipse

To make use of this view to show SFR and other registers we will use “SVD Path” option from “debug configurations” of eclipse. In Eclipse click on “Run”-> “Debug Configurations” and select “SVD path” tab. It is assumed that you have completed debug configurations.

Here you have to provide svd file path of your controller. In my case we are using SAME54 controller. The best place to get latest updated SVD file is from installation directory of the IDE. For 32bit Microchip controllers svd files can be found in following path – “C:/Program Files(x86)/Atmel/Studio/7.0/packs/atmel/SAME54_DFP/1.0.87/svd/ATSAME54P20A.svd”. Location “Atmel/Studio/7.0/packs/” have all svd file eg. SAM3A, SAM4C, SAMD, SAME, SAMG, SAMH, SAML, SAMR and SAMS controller series. Select the svd file as per your controller.

SVD Path update for SAME54 controller

Once this is updated click on “debug” to start debugging. One can also provide variables instead of absolute path for .svd files. CMSIS-SVD – Cortex Microcontroller Software Interface Standard – System View Description format- files provides consistent view to device and peripherals.
In debug mode stop at any breakpoints and you can view peripherals now. All the updates are marked in yellow.

EmbSysRegView Alternative

Although EmbSysRegView provides good interface in eclipse there is always better to have alternate solution if one plugin is not working. With the Embedded Systems Register View and this peripherals view you have a gateway to inspect peripheral registers of device under debug. This is possible with open source software like eclipse, gdb, openocd and CMSIS-SVD files.

EmbSysRegView In Eclipse For SAME54 On Ubuntu

After successfully able to debug using OpenOCD and Eclipse, Now it is time to explore more. To start with, lets install EmbSysRegView plugin, This plugin gives similar functionality to the ‘I/O view’ in Atmel Studio 7. It displays special functions registers (SFR), peripheral registers values and memory values. This needed in embedded system development.


Bad news is, You can not install the EmbSysRegView plugin from the eclipse marketplace since eclipse marketplace is referring to old sourceforge download URL.

Installation from Marketplace fails: 
An error occurred while collecting items to be installed
session context was:(profile=_Applications_Eclipse.app_Contents_Eclipse, phase=org.eclipse.equinox.internal.p2.engine.phases.Collect, operand=, action=).
Artifact not found:

The new link to download is from sourceforge latest download, But it does not download full files and this is also failing. Even if you try to download the source from git

$git clone embsysregview-git
It says downloaded folder is empty :-(.

Tried to do google and found out one workaround, But according to workaround for this problem tried to update the plugin in eclipse but failed, so tried with the updated script as


But this is also failing.

Embsysregview not working

Simple solution is download all four files from sourceforge project folder to your local folder.

EmbsysregView download from parent folder

Copy these four files to “Dropins” folder inside Eclipse and restart Eclipse.

Then use the menu Window > Show View -> other -> Debug and open the EmbSys Registers view: you will get ERROR: please select chip using prefrence page (C++/Debug/EmbSys Register View), so select the proper chip.

Adding Support For SAME54 in EmbSysReg

EmbSysRegView does not come with Atmel/Microchip SAM E54 microcontroller, so This short article explains how to add support for SAM E54 seris in EmbSysRegView with Eclipse on latest Ubuntu.

For this we need to get CMSIS SVD files -The CMSIS System View Description format(CMSIS-SVD) – is the memory mapped registers of peripherals contained in ARM Cortex-M processor-based microcontrollers. That contain standardized descriptions for peripherals and their registers for Cortex-M microcontrollers. All device support from Atmel is available in packs. So Download the pack for SAME54 series and unzip it.

This file we need to copy into ‘ org.eclipse.cdt.embsysregview.data_0.2.6.r191.jar'

Open Terminal at the folder with the jar file and run the following commands, this will add svd files and update .jar with added support of SAME54

$unzip org.eclipse.cdt.embsysregview.data_0.2.6.r191.jar -d temp
//Navigate to ‘Atmel.SAME54_DFP.1.0.87’->svd folder
//Then copy these files to ‘temp->data->SVD (CMSIS)->Atmel’
//Change the extension from .svd to .xml
//create .jar file out which includes this update
$jar cvf org.eclipse.cdt.embsysregview.data_0.2.6.r191.jar -C temp/ .

Now copy this updated .jar file to “dropins” folder in Eclipse and restart IDE.

SAME54 Support added in EmbSysRegView

You can now able to select ATSAME54 controller to view all registers. Happy debugging.