diff --git a/executables/nr-ue.c b/executables/nr-ue.c
index fcbd659bbea7832b5b8f75c5394058fb5530a5f3..a781c5fdcdc46373e997ceae42dfe1f6e6a50897 100644
--- a/executables/nr-ue.c
+++ b/executables/nr-ue.c
@@ -461,6 +461,15 @@ void UE_processing(void *arg) {
   UE_nr_rxtx_proc_t *proc = &rxtxD->proc;
   PHY_VARS_NR_UE    *UE   = rxtxD->UE;
   processSlotRX(UE, proc);
+  uint8_t gNB_id = 0;
+
+  // params for UL time alignment procedure
+  NR_UL_TIME_ALIGNMENT_t *ul_time_alignment = &UE->ul_time_alignment[gNB_id];
+  uint8_t numerology = UE->frame_parms.numerology_index;
+  uint16_t bwp_ul_NB_RB = UE->frame_parms.N_RB_UL;
+  int slot_tx = proc->nr_tti_tx;
+  int frame_tx = proc->frame_tx;
+
   //printf(">>> mac ended\n");
   // Prepare the future Tx data
 /*
@@ -473,6 +482,21 @@ void UE_processing(void *arg) {
 #endif
 */
 
+  /* UL time alignment
+  // If the current tx frame and slot match the TA configuration in ul_time_alignment
+  // then timing advance is processed and set to be applied in the next UL transmission */
+  if (UE->mac_enabled == 1) {
+
+    if (frame_tx == ul_time_alignment->ta_frame && slot_tx == ul_time_alignment->ta_slot){
+      LOG_D(PHY,"Applying timing advance -- frame %d -- slot %d\n", frame_tx, slot_tx);
+
+      //if (nfapi_mode!=3){
+      nr_process_timing_advance(UE->Mod_id, UE->CC_id, ul_time_alignment->ta_command, numerology, bwp_ul_NB_RB);
+      ul_time_alignment->ta_frame = -1;
+      ul_time_alignment->ta_slot = -1;
+      //}
+    }
+  }
 
   if (proc->nr_tti_tx == NR_UPLINK_SLOT || UE->frame_parms.frame_type == FDD){
 
@@ -480,7 +504,7 @@ void UE_processing(void *arg) {
 
 
     if (UE->mode != loop_through_memory)
-      phy_procedures_nrUE_TX(UE,proc,0,thread_id);
+      phy_procedures_nrUE_TX(UE,proc,gNB_id,thread_id);
 
   }
 
diff --git a/openair1/PHY/defs_nr_UE.h b/openair1/PHY/defs_nr_UE.h
index 19f4365a298ac47b8054d87f9e1c4ed6a4f32341..663e005d65ae8d409e7dde0d03715543ef55897d 100644
--- a/openair1/PHY/defs_nr_UE.h
+++ b/openair1/PHY/defs_nr_UE.h
@@ -871,6 +871,16 @@ typedef struct UE_NR_SCAN_INFO_s {
   int32_t freq_offset_Hz[3][10];
 } UE_NR_SCAN_INFO_t;
 
+typedef struct {
+  /// flag used by MAC to inform PHY about a TA to be applied
+  unsigned char    apply_ta;
+  /// frame and slot when to apply the TA as stated in TS 38.213 setion 4.2
+  int16_t         ta_frame;
+  char            ta_slot;
+  /// TA command and TAGID received from the gNB
+  uint8_t          ta_command;
+  uint8_t          tag_id;
+} NR_UL_TIME_ALIGNMENT_t;
 
 #include "NR_IF_Module.h"
 
@@ -1066,9 +1076,14 @@ typedef struct {
   int              rx_offset; /// Timing offset
   int              rx_offset_diff; /// Timing adjustment for ofdm symbol0 on HW USRP
   int              time_sync_cell;
-  int              timing_advance; ///timing advance signalled from eNB
-  int              hw_timing_advance;
-  int              N_TA_offset; ///timing offset used in TDD
+
+  /// Timing Advance updates variables
+  /// Timing advance update computed from the TA command signalled from gNB
+  int                      timing_advance;
+  int                      hw_timing_advance;
+  int                      N_TA_offset; ///timing offset used in TDD
+  NR_UL_TIME_ALIGNMENT_t   ul_time_alignment[NUMBER_OF_CONNECTED_gNB_MAX];
+
   /// Flag to tell if UE is secondary user (cognitive mode)
   unsigned char    is_secondary_ue;
   /// Flag to tell if secondary eNB has channel estimates to create NULL-beams from.
diff --git a/openair1/SCHED_NR_UE/defs.h b/openair1/SCHED_NR_UE/defs.h
index 66398c393e9cebe56bfd6e2b8004a18497d93484..4b4800398e94c34b5886a4dc8689f28b4e9dd6e8 100644
--- a/openair1/SCHED_NR_UE/defs.h
+++ b/openair1/SCHED_NR_UE/defs.h
@@ -292,10 +292,10 @@ int8_t nr_find_ue(uint16_t rnti, PHY_VARS_eNB *phy_vars_eNB);
 /*! \brief Compute the timing adjustment at UE side from the old TA offset and the new received TA command
   @param Mod_id Local UE index on which to act
   @param CC_id Component Carrier Index
-  @param timing_advance TA command
+  @param ta_command TA command received from the network
   @param mu numerology index (0,1,2..)
 */
-void nr_process_timing_advance(module_id_t Mod_id,uint8_t CC_id,uint8_t timing_advance, uint8_t mu, uint16_t bwp_ul_NB_RB);
+void nr_process_timing_advance(module_id_t Mod_id,uint8_t CC_id,uint8_t ta_command, uint8_t mu, uint16_t bwp_ul_NB_RB);
 void nr_process_timing_advance_rar(PHY_VARS_NR_UE *phy_vars_ue,UE_nr_rxtx_proc_t *proc,uint16_t timing_advance);
 
 unsigned int get_tx_amp(int power_dBm, int power_max_dBm, int N_RB_UL, int nb_rb);
diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
index 138f40790f47ffccc2196c9fa93aa00893c6a43c..c4df96c56a0efc59a12bbfdf680fb36900919d74 100644
--- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
+++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
@@ -1545,7 +1545,7 @@ VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDUR
 #endif
 
 
-void nr_process_timing_advance(module_id_t Mod_id, uint8_t CC_id, uint8_t timing_advance, uint8_t mu, uint16_t bwp_ul_NB_RB){
+void nr_process_timing_advance(module_id_t Mod_id, uint8_t CC_id, uint8_t ta_command, uint8_t mu, uint16_t bwp_ul_NB_RB){
 
   // 3GPP TS 38.213 p4.2
   // scale by the scs numerology
@@ -1561,9 +1561,9 @@ void nr_process_timing_advance(module_id_t Mod_id, uint8_t CC_id, uint8_t timing
     default: abort();
   }
 
-  PHY_vars_UE_g[Mod_id][CC_id]->timing_advance += (timing_advance - 31) * bw_scaling / factor_mu;
+  PHY_vars_UE_g[Mod_id][CC_id]->timing_advance += (ta_command - 31) * bw_scaling / factor_mu;
 
-  LOG_D(PHY,"[UE %d] Got timing advance %u from MAC, new value is %u\n",Mod_id, timing_advance, PHY_vars_UE_g[Mod_id][CC_id]->timing_advance);
+  LOG_D(PHY, "[UE %d] Got timing advance command %u from MAC, new value is %u\n", Mod_id, ta_command, PHY_vars_UE_g[Mod_id][CC_id]->timing_advance);
 }
 
 void ue_ulsch_uespec_procedures(PHY_VARS_NR_UE *ue,
@@ -3545,6 +3545,11 @@ void nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue,
   uint16_t nb_symb_sch = 9;
   nr_downlink_indication_t dl_indication;
   fapi_nr_rx_indication_t rx_ind;
+  // params for UL time alignment procedure
+  NR_UL_TIME_ALIGNMENT_t *ul_time_alignment = &ue->ul_time_alignment[eNB_id];
+  unsigned char *apply_ta = &ul_time_alignment->apply_ta;
+  uint16_t slots_per_frame = ue->frame_parms.slots_per_frame;
+  int ul_tx_timing_adjustment = 6; // temporary hardcoded
 
   if (dlsch0==NULL)
     AssertFatal(0,"dlsch0 should be defined at this level \n");
@@ -3850,7 +3855,8 @@ void nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue,
                       nr_tti_rx,
                       dlsch0->harq_processes[harq_pid]->b,
                       dlsch0->harq_processes[harq_pid]->TBS>>3,
-                      eNB_id);
+                      eNB_id,
+                      ul_time_alignment);
           break;
           case SI_PDSCH:
           /*ue_decode_si(ue->Mod_id,
@@ -3880,6 +3886,20 @@ void nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue,
           AssertFatal(1==0,"exiting");*/
           break;
         }
+
+        /* Time alignment procedure set the TA to be applied 6 slots 
+        // after the reception of the command */
+        if (ul_time_alignment->apply_ta == 1){
+          ul_time_alignment->ta_slot = (nr_tti_rx + ul_tx_timing_adjustment) % slots_per_frame;
+          if (nr_tti_rx + ul_tx_timing_adjustment > slots_per_frame){
+            ul_time_alignment->ta_frame = (frame_rx + 1) % 1024;
+          } else {
+            ul_time_alignment->ta_frame = frame_rx;
+          }
+          // reset TA flag
+          ul_time_alignment->apply_ta = 0;
+          LOG_D(PHY,"Frame %d slot %d -- Starting UL time alignment procedures. TA update will be applied at frame %d slot %d\n", frame_rx, nr_tti_rx, ul_time_alignment->ta_frame, ul_time_alignment->ta_slot);
+        }
       }
 
       /*ue->total_TBS[eNB_id] =  ue->total_TBS[eNB_id] + dlsch0->harq_processes[dlsch0->current_harq_pid]->TBS;
diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h
index 6cbe7b32c43e36c49b2305883a471c40e0e82403..6e369ac2745361cbc06082e4d875fd04b26e36f3 100755
--- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h
+++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h
@@ -137,14 +137,15 @@ uint32_t mr_ue_get_SR(module_id_t module_idP, int CC_id, frame_t frameP, uint8_t
 @returns void
 */
 void nr_ue_send_sdu(module_id_t module_idP,uint8_t CC_id, frame_t frameP, uint8_t ttiP,
-                    uint8_t * pdu, uint16_t pdu_len, uint8_t eNB_index);
+                    uint8_t * pdu, uint16_t pdu_len, uint8_t eNB_index, NR_UL_TIME_ALIGNMENT_t *ul_time_alignment);
 
 void nr_ue_process_mac_pdu(
     module_id_t module_idP,
     uint8_t CC_id,
     uint8_t *pduP, 
     uint16_t mac_pdu_len,
-    uint8_t eNB_index);
+    uint8_t eNB_index,
+    NR_UL_TIME_ALIGNMENT_t *ul_time_alignment);
 
 int8_t nr_ue_process_dlsch(module_id_t module_id, int cc_id, uint8_t gNB_index, fapi_nr_dci_indication_t *dci_ind, void *pduP, uint32_t pdu_len);
 
diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
index f63620b1d0c77f5eca707a5bb5fac29406099059..758d165ceab140bb1bd61e103a12ec6356903ebd 100644
--- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
+++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
@@ -2047,7 +2047,7 @@ void nr_ue_send_sdu(module_id_t module_idP,
                     uint8_t CC_id,
                     frame_t frameP,
                     uint8_t ttiP,
-                    uint8_t * pdu, uint16_t pdu_len, uint8_t eNB_index){
+                    uint8_t * pdu, uint16_t pdu_len, uint8_t eNB_index, NR_UL_TIME_ALIGNMENT_t *ul_time_alignment){
 
   printf("nr_ue_send_sdu frame %d\n", frameP);
 
@@ -2094,7 +2094,7 @@ void nr_ue_send_sdu(module_id_t module_idP,
 
   // Processing MAC PDU
   // it parses MAC CEs subheaders, MAC CEs, SDU subheaderds and SDUs
-  nr_ue_process_mac_pdu(module_idP, CC_id, pduP, pdu_len, eNB_index);
+  nr_ue_process_mac_pdu(module_idP, CC_id, pduP, pdu_len, eNB_index, ul_time_alignment);
 
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SEND_SDU, VCD_FUNCTION_OUT);
 
@@ -2110,7 +2110,8 @@ void nr_ue_process_mac_pdu(
     uint8_t CC_id,
     uint8_t *pduP, 
     uint16_t mac_pdu_len,
-    uint8_t eNB_index){
+    uint8_t eNB_index,
+    NR_UL_TIME_ALIGNMENT_t *ul_time_alignment){
 
     // This function is adapting code from the old
     // parse_header(...) and ue_send_sdu(...) functions of OAI LTE
@@ -2123,8 +2124,9 @@ void nr_ue_process_mac_pdu(
     uint16_t mac_sdu_len;
 
     NR_UE_MAC_INST_t *UE_mac_inst = get_mac_inst(module_idP);
-    uint8_t scs = UE_mac_inst->mib->subCarrierSpacingCommon;
-    uint16_t bwp_ul_NB_RB = UE_mac_inst->initial_bwp_ul.N_RB;
+    //uint8_t scs = UE_mac_inst->mib->subCarrierSpacingCommon;
+    //uint16_t bwp_ul_NB_RB = UE_mac_inst->initial_bwp_ul.N_RB;
+
     //  For both DL/UL-SCH
     //  Except:
     //   - UL/DL-SCH: fixed-size MAC CE(known by LCID)
@@ -2280,9 +2282,12 @@ void nr_ue_process_mac_pdu(
                 //  38.321 Ch6.1.3.4
                 mac_ce_len = 1;
 
-                uint8_t ta_command = ((NR_MAC_CE_TA *)pdu_ptr)[1].TA_COMMAND;
+                /*uint8_t ta_command = ((NR_MAC_CE_TA *)pdu_ptr)[1].TA_COMMAND;
+                uint8_t tag_id = ((NR_MAC_CE_TA *)pdu_ptr)[1].TAGID;*/
 
-                uint8_t tag_id = ((NR_MAC_CE_TA *)pdu_ptr)[1].TAGID;
+                ul_time_alignment->apply_ta = 1;
+                ul_time_alignment->ta_command = ((NR_MAC_CE_TA *)pdu_ptr)[1].TA_COMMAND;
+                ul_time_alignment->tag_id = ((NR_MAC_CE_TA *)pdu_ptr)[1].TAGID;
 
                 /*
                 #ifdef DEBUG_HEADER_PARSING
@@ -2290,11 +2295,8 @@ void nr_ue_process_mac_pdu(
                 #endif
                 */
 
-                LOG_D(MAC, "Received TA_COMMAND %u TAGID %u CC_id %d\n", ta_command, tag_id, CC_id);
-
-                //if (nfapi_mode!=3){ // TODO check nfapi_mode
-                  nr_process_timing_advance(module_idP, CC_id, ta_command, scs, bwp_ul_NB_RB);
-                //}
+                LOG_D(MAC, "Received TA_COMMAND %u TAGID %u CC_id %d\n",
+                  ul_time_alignment->ta_command, ul_time_alignment->tag_id, CC_id);
 
                 break;
             case DL_SCH_LCID_CON_RES_ID:
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c
index d2f6d805dedb4e38ab81cddb5cb5eefd9014af1f..3c654ac66cc4565a1557cef246c1910516124c20 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c
@@ -53,6 +53,7 @@ int nr_generate_dlsch_pdu(unsigned char *sdus_payload,
                           unsigned char drx_cmd,
                           unsigned short timing_advance_cmd,
                           NR_TAG_Id_t tag_id,
+                          int ta_length,
                           unsigned char *ue_cont_res_id,
                           unsigned short post_padding){
 
@@ -76,25 +77,30 @@ int nr_generate_dlsch_pdu(unsigned char *sdus_payload,
   }
 
   // Timing Advance subheader
-  if (timing_advance_cmd != 31) {
+  /* This was done only when timing_advance_cmd != 31
+  // now TA is always send when ta_timer resets regardless of its value
+  // this is done to avoid issues with the timeAlignmentTimer which is
+  // supposed to monitor if the UE received TA or not */
+  if (ta_length){
     mac_pdu_ptr->R = 0;
     mac_pdu_ptr->LCID = DL_SCH_LCID_TA_COMMAND;
     //last_size = 1;
     mac_pdu_ptr++;
 
-    // TA MAC CE (1 octet) 
+    // TA MAC CE (1 octet)
     AssertFatal(timing_advance_cmd < 64,"timing_advance_cmd %d > 63\n", timing_advance_cmd);
     ((NR_MAC_CE_TA *) ce_ptr)->TA_COMMAND = timing_advance_cmd;    //(timing_advance_cmd+31)&0x3f;
     ((NR_MAC_CE_TA *) ce_ptr)->TAGID = tag_id;
 
     LOG_D(MAC, "NR MAC CE timing advance command =%d (%d) TAG ID =%d\n", timing_advance_cmd, ((NR_MAC_CE_TA *) ce_ptr)->TA_COMMAND, tag_id);
     mac_ce_size = sizeof(NR_MAC_CE_TA);
-    
+
     // Copying  bytes for MAC CEs to the mac pdu pointer
     memcpy((void *) mac_pdu_ptr, (void *) ce_ptr, mac_ce_size);
     ce_ptr += mac_ce_size;
-    mac_pdu_ptr += (unsigned char) mac_ce_size;  
-   }
+    mac_pdu_ptr += (unsigned char) mac_ce_size;
+  }
+
 
   // Contention resolution fixed subheader and MAC CE
   if (ue_cont_res_id) {
@@ -199,35 +205,35 @@ nr_schedule_ue_spec(module_id_t module_idP, frame_t frameP, sub_frame_t slotP){
   int UE_id = 0; // UE_list->head is -1 !
 
   UE_sched_ctrl_t *ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
-  ta_update = ue_sched_ctl->ta_update;
+  //ta_update = ue_sched_ctl->ta_update;
   
-  for (CC_id = 0; CC_id < RC.nb_nr_mac_CC[module_idP] + 1; CC_id++) {
-    LOG_D(MAC, "doing nr_schedule_ue_spec for CC_id %d\n", CC_id);
+  for (CC_id = 0; CC_id < RC.nb_nr_mac_CC[module_idP]; CC_id++) {
+    LOG_D(MAC, "doing nr_schedule_ue_spec for UE_id %d CC_id %d frame %d slot %d\n",
+      UE_id, CC_id, frameP, slotP);
     dl_req = &gNB->DL_req[CC_id].dl_config_request_body;
 
     //for (UE_id = UE_list->head; UE_id >= -1; UE_id = UE_list->next[UE_id]) {
 
-      /* 
+    // this was taken from the preprocessor
+    if (ue_sched_ctl->ta_timer) ue_sched_ctl->ta_timer--;
+
+      /*
       //process retransmission
       if (round != 8) {
-   
+
       } else {	// This is a potentially new SDU opportunity */
 
-        if (gNB->tag->timeAlignmentTimer != NULL) {
-          printf(" SHOULD NOT ENTER HERE \n");
-          if (gNB->tag->timeAlignmentTimer == 0) {
-            ta_update = ue_sched_ctl->ta_update;
-            /* if we send TA then set timer to not send it for a while */
-            if (ta_update != 31)
-              ue_sched_ctl->ta_timer = 20;
-            /* reset ta_update */
-            ue_sched_ctl->ta_update = 31; 
-          } else {
-            ta_update = 31;
-          }
-        }
+        if (ue_sched_ctl->ta_timer == 0) {
+          ta_update = ue_sched_ctl->ta_update;
+          /* if time is up, then set the timer to not send it for 20 NR_DOWNLINK_SLOT (20 frames)
+          // regardless of the TA value */
+          ue_sched_ctl->ta_timer = 2; //set to 20 when transmission will be in every slot
+          /* reset ta_update */
+          ue_sched_ctl->ta_update = 31;
+          ta_len = 2;
+        } // else ta_update = 31;
 
-        ta_len = (ta_update != 31) ? 2 : 0;
+        //ta_len = (ta_update != 31) ? 2 : 0;
 
         // retrieve TAG ID
         if(gNB->tag->tag_Id != NULL ){
@@ -307,6 +313,7 @@ nr_schedule_ue_spec(module_id_t module_idP, frame_t frameP, sub_frame_t slotP){
           	                            255,          // no drx
           	                            ta_update,    // timing advance
                                         tag_id,
+                                        ta_len,
           	                            NULL,         // contention res id
           	                            post_padding);
           // Padding: fill remainder of DLSCH with 0 
diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h
index 185c866661a5aae2b7d46e46d1e9226e8b4f8769..530911f359c52cb343e243fad38e45e13ad4b2f0 100644
--- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h
+++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h
@@ -79,6 +79,7 @@ int nr_generate_dlsch_pdu(unsigned char *sdus_payload,
                           unsigned char drx_cmd,
                           unsigned short timing_advance_cmd,
                           NR_TAG_Id_t tag_id,
+                          int ta_length,
                           unsigned char *ue_cont_res_id,
                           unsigned short post_padding);