This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

TWIM EasyDMA Delay Between Bytes

Hi,

I'm writing a library for the common Hitachi_HD44780 (LCD2004 etc) but need it to be non-blocking. I'll open source it once done. I'm using EasyDMA to do the transfers but the aging HD44780 needs a 50us delay in-between commands. My idea so far is;

1. set a timer with a period of 50us and a counter equal to the amount of bytes with a PPI to halt the timer and fire an interrupt to indicate "done"
2. timer period event fires EasyDMA which transfers one byte.

My question then is around EasyDMA List mode. Can I clarify that what it's doing is adding MAXCNT to the PTR object after each send?

In other words if I set MAXCNT = 1 and use list mode I should get the spaces inbetween the bytes without needing to interrupt to PTR++?

Parents
  • My question then is around EasyDMA List mode. Can I clarify that what it's doing is adding MAXCNT to the PTR object after each send?

    In other words if I set MAXCNT = 1 and use list mode I should get the spaces inbetween the bytes without needing to interrupt to PTR++?

     Yes, but I believe each byte will be a new transfer, so a new address+R/W-bit and 1 byte data for each iteration, but I'm not quite sure. I guess you'll have to try and see if it works.

Reply
  • My question then is around EasyDMA List mode. Can I clarify that what it's doing is adding MAXCNT to the PTR object after each send?

    In other words if I set MAXCNT = 1 and use list mode I should get the spaces inbetween the bytes without needing to interrupt to PTR++?

     Yes, but I believe each byte will be a new transfer, so a new address+R/W-bit and 1 byte data for each iteration, but I'm not quite sure. I guess you'll have to try and see if it works.

Children
  • I have the approach sorted - two timers, three PPI channels and a TWIM.

    The problem and I've yet to crack it is as soon as the counter compare event is one and the interrupt fires the CPU appears to lock (I am not in any interrupt or loop).

    #define CFG_PIN_LCD_SDA 5
    #define CFG_PIN_LCD_SCL 6
    #define CFG_PIN_LCD_VDD 7
    
    #define CFG_PPI_LCD_CHANNEL_TWIM_START 2
    #define CFG_PPI_LCD_CHANNEL_COUNTER_TICK 3
    #define CFG_PPI_LCD_CHANNEL_COUNTER_RESET 4
    #define CFG_TIMER_LCD_SPACE NRF_TIMER3
    #define CFG_TIMER_LCD_COUNTER NRF_TIMER4
    #define CFG_TWIM_LCD_TX NRF_TWIM0

    Been over and over the config below. It looks perfect to my eyes.

      NRF_GPIO->PIN_CNF[CFG_PIN_LCD_SCL] = I2C_PIN_INIT_CONF;
      NRF_GPIO->PIN_CNF[CFG_PIN_LCD_SDA] = I2C_PIN_INIT_CONF;
      NRF_GPIO->PIN_CNF[CFG_PIN_LCD_VDD] = ((GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos));
      NRF_GPIO->OUTSET = 1 << CFG_PIN_LCD_VDD;
    
      CFG_TIMER_LCD_SPACE->PRESCALER = 0;
      CFG_TIMER_LCD_SPACE->CC[0] = 1;
      CFG_TIMER_LCD_SPACE->CC[1] = LCD_TICKS_BETWEEN_DATA - 50U;
      CFG_TIMER_LCD_SPACE->CC[2] = LCD_TICKS_BETWEEN_DATA;
      CFG_TIMER_LCD_SPACE->SHORTS = TIMER_SHORTS_COMPARE2_CLEAR_Enabled << TIMER_SHORTS_COMPARE2_CLEAR_Pos;
      CFG_TIMER_LCD_COUNTER->PRESCALER = 0;
      CFG_TIMER_LCD_COUNTER->MODE = TIMER_MODE_MODE_LowPowerCounter << TIMER_MODE_MODE_Pos;
      CFG_TIMER_LCD_COUNTER->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos;
      CFG_TIMER_LCD_COUNTER->INTENSET = TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos;
      CFG_TIMER_LCD_COUNTER->TASKS_START = 1;
      
      CFG_TWIM_LCD_TX->ADDRESS = 0x3f;
      CFG_TWIM_LCD_TX->FREQUENCY = TWIM_FREQUENCY_FREQUENCY_K100 << TWIM_FREQUENCY_FREQUENCY_Pos;
      CFG_TWIM_LCD_TX->PSEL.SCL = (TWIM_PSEL_SCL_CONNECT_Connected << TWIM_PSEL_SCL_CONNECT_Pos) | CFG_PIN_LCD_SCL;
      CFG_TWIM_LCD_TX->PSEL.SDA = (TWIM_PSEL_SDA_CONNECT_Connected << TWIM_PSEL_SDA_CONNECT_Pos) | CFG_PIN_LCD_SDA;
      CFG_TWIM_LCD_TX->SHORTS = TWIM_SHORTS_LASTTX_STOP_Enabled << TWIM_SHORTS_LASTTX_STOP_Pos;
      CFG_TWIM_LCD_TX->TXD.LIST = TWIM_TXD_LIST_LIST_ArrayList << TWIM_TXD_LIST_LIST_Pos;
      CFG_TWIM_LCD_TX->TXD.MAXCNT = LCD_PAYLOAD_CMD_DATA;
      CFG_TWIM_LCD_TX->ENABLE = TWIM_ENABLE_ENABLE_Enabled << TWIM_ENABLE_ENABLE_Pos;
    
      //NRF_PPI->CH[CFG_PPI_LCD_CHANNEL_TWIM_START].EEP = (uint32_t) &CFG_TIMER_LCD_SPACE->EVENTS_COMPARE[0]; // wire timer compare
      //NRF_PPI->CH[CFG_PPI_LCD_CHANNEL_TWIM_START].TEP = (uint32_t) &CFG_TWIM_LCD_TX->TASKS_STARTTX; 
      NRF_PPI->CH[CFG_PPI_LCD_CHANNEL_COUNTER_TICK].EEP = (uint32_t) &CFG_TIMER_LCD_SPACE->EVENTS_COMPARE[1]; // wire timer compare
      NRF_PPI->CH[CFG_PPI_LCD_CHANNEL_COUNTER_TICK].TEP = (uint32_t) &CFG_TIMER_LCD_COUNTER->TASKS_COUNT; 
      NRF_PPI->CH[CFG_PPI_LCD_CHANNEL_COUNTER_RESET].EEP = (uint32_t) &CFG_TIMER_LCD_COUNTER->EVENTS_COMPARE[0]; // wire timer compare
      NRF_PPI->CH[CFG_PPI_LCD_CHANNEL_COUNTER_RESET].TEP = (uint32_t) &CFG_TIMER_LCD_SPACE->TASKS_STOP;
      NRF_PPI->FORK[CFG_PPI_LCD_CHANNEL_COUNTER_RESET].TEP = (uint32_t) &CFG_TIMER_LCD_SPACE->TASKS_CLEAR;
    
      NRF_PPI->CHENSET = 1 << CFG_PPI_LCD_CHANNEL_TWIM_START | 1 << CFG_PPI_LCD_CHANNEL_COUNTER_TICK | 1 << CFG_PPI_LCD_CHANNEL_COUNTER_RESET;  // enable ppi channel
    
      NVIC_EnableIRQ(TIMER4_IRQn);
    
       __enable_irq();
    


    printf is working, stuck in the interrupt since can''t break inside of it. It doesn't hit.

    void TIMER4_IRQHandler (void) {
    
      printf("hurrah", 0);
      dmaBuffer.transferBuffer->size = 0;
      dmaBuffer.transferBuffer = getNextBuffer(dmaBuffer.transferBuffer);
      dmaBuffer.writing = 0;
      if (!dmaBuffer.locked && dmaBuffer.transferBuffer->size) {
        __startTransfer();
      }
    }


Related