/* * Rising edge on the data line while the clock line is high indicates * a stop condition. * * Entry: SCL low, SDA any * Exit: SCL high, SDA high */ static void TwStop(GPIO_TWICB* icb) { I2C_SDA_LO(); NutMicroDelay (icb->delay_unit); I2C_SCL_HI(); NutMicroDelay (2 * icb->delay_unit); I2C_SDA_HI(); NutMicroDelay (8 * icb->delay_unit); }
/*! * \brief Send byte to LCD controller. * * \param data Byte to send. */ static void LcdWriteByte(unsigned int data) { /* If configured set RW low */ #ifdef LCD_RW_BIT LCD_RW_CLR(); #endif /* If using 4-bit access, write two nibbles now */ #ifdef LCD_IF_4BIT LcdWriteNibble(data >> 4); LcdNanoDelay(LCD_PW_EH); LcdWriteNibble(data); #else /* else write one byte */ LcdWriteNibble(data); #endif /* If configured, let the task sleep before next character */ #if defined(LCD_SLEEP_DLY) NutSleep(1); #else /* or add a fixed delay and immediately process next char */ NutMicroDelay(LCD_E2E_DLY); #endif }
/*! * \brief Send half byte to LCD controller. * * \param nib The four least significant bits are sent. */ static void LcdWriteNibble(unsigned int nib) { #ifdef LCD_DATA_LSB nib <<= LCD_DATA_LSB; #else { unsigned int val = 0; if (nib & 0x01) { val |= LCD_D0; } if (nib & 0x02) { val |= LCD_D1; } if (nib & 0x04) { val |= LCD_D2; } if (nib & 0x08) { val |= LCD_D3; } nib = val; } #endif LcdSetBits(nib & LCD_DATA); LcdClrBits(~nib & LCD_DATA); /* Create Enable Pulse: * For HD44780 Displays we need: * Vcc = 5.0V -> PWeh >= 230ns * Vcc = 3.3V -> PWeh >= 500ns */ LCD_EN_SET(); NutMicroDelay(LCD_SHORT_DELAY); LCD_EN_CLR(); }
/* * Toggles in a single byte in master mode. * * Entry: SCL low, SDA any * Exit: SCL low, SDA low with ack set, high else * * Change SDA only when SCL is low! * Sample SDA short before setting SCL low! */ static uint8_t TwGet(GPIO_TWICB* icb, uint8_t ack) { uint8_t rc = 0; int i; /* SDA is input. */ I2C_SDA_HI(); NutMicroDelay (1 * icb->delay_unit); for (i = 0x80; i; i >>= 1) { NutMicroDelay (2 * icb->delay_unit); I2C_SCL_HI(); NutMicroDelay (2 * icb->delay_unit); while(I2C_SCL_GET() == 0) { /* Clock stretching*/ NutMicroDelay (2 * icb->delay_unit); } if (I2C_SDA_GET()) { rc |= i; } I2C_SCL_LO(); } if (ack) { /* Master sets acknowledge */ I2C_SDA_LO(); } NutMicroDelay (2 * icb->delay_unit); I2C_SCL_HI(); NutMicroDelay (2 * icb->delay_unit); I2C_SCL_LO(); NutMicroDelay (2 * icb->delay_unit); return rc; }
static int LcdInit(NUTDEVICE * dev) { LCD_RS_CLR(); LCD_RW_CLR(); LcdClrBits(LCD_DATA); NutMicroDelay(30); LCD_EN_CLR(); NutMicroDelay(30); NutSleep(18); /* This initialization will make sure, that the LCD is switched * to 8-bit mode, no matter which mode we start from or we finally * need. */ LcdWriteCmd(_BV(LCD_FUNCTION) | _BV(LCD_FUNCTION_8BIT)); NutSleep(16); LcdWriteCmd(_BV(LCD_FUNCTION) | _BV(LCD_FUNCTION_8BIT)); NutSleep(4); LcdWriteCmd(_BV(LCD_FUNCTION) | _BV(LCD_FUNCTION_8BIT)); NutSleep(2); LcdWriteInstruction((_BV(LCD_FUNCTION)) | (_BV(LCD_FUNCTION_8BIT)) | (_BV(LCD_EXT)) , LCD_SHORT_DELAY); /* Switch display and cursor off. */ LcdWriteNibble(_BV(LCD_ON_CTRL) >> 4); LcdWriteNibble(_BV(LCD_ON_CTRL)); NutSleep(2); /* Clear display. */ LcdClear(); /* Set entry mode. */ LcdWriteCmd(_BV(LCD_ENTRY_MODE) | _BV(LCD_ENTRY_INC)); /* Switch display on. */ LcdWriteCmd(_BV(LCD_ON_CTRL) | _BV(LCD_ON_DISPLAY)); /* Move cursor home. */ LcdCursorHome(); /* Set data address to zero. */ LcdWriteCmd(_BV(LCD_DDRAM)); return 0; }
/* This function is a bit critical as some chipsets are known to * release the redy bit some time early. So after rady goes low, * another fixed delay has to be added before soing the next access. */ static void LcdWaitReady(unsigned int delay) { while (delay--) { #if defined(HD44_RW_BIT) if ((LcdReadStatus() & _BV(LCD_BUSY)) == 0) { break; } #endif NutMicroDelay(1); } }
/* * Demonstrate Nut/OS delay timer. * * The delay function will not release the CPU, keeping all other threads * blocked. It is a good choice for very short delays, where context * switching is undesirable or would take too long. Use it sparingly and * for short delays only. */ static void DelayDemo(void) { uint32_t req; uint32_t act; for (req = 1024UL; req <= 8UL * 1024UL * 1024UL; req *= 2) { printf("Delaying %lu us, ", req); act = NutGetMillis(); NutMicroDelay(req); act = NutGetMillis() - act; printf("delayed %lu ms\n", act); } }
/* Idle clock is high and data is captured on the rising edge. */ static void SpiMode3Transfer(GSPIREG *gspi, CONST uint8_t *txbuf, uint8_t *rxbuf, int xlen) { #if defined(SBBI0_SCK_BIT) uint_fast8_t mask; while (xlen--) { for (mask = 0x80; mask; mask >>= 1) { NutMicroDelay(gspi->gspi_dly_rate); GpioPinSetLow(SBBI0_SCK_PORT, SBBI0_SCK_BIT); #if defined(SBBI0_MOSI_BIT) if (txbuf) { GpioPinSet(SBBI0_MOSI_PORT, SBBI0_MOSI_BIT, (*txbuf & mask) != 0); } #endif /* SBBI0_MOSI_BIT */ NutMicroDelay(gspi->gspi_dly_rate); GpioPinSetHigh(SBBI0_SCK_PORT, SBBI0_SCK_BIT); #if defined(SBBI0_MISO_BIT) if (rxbuf) { if (GpioPinGet(SBBI0_MISO_PORT, SBBI0_MISO_BIT)) { *rxbuf |= mask; } else { *rxbuf &= ~mask; } } #endif /* SBBI0_MISO_BIT */ } if (txbuf) { txbuf++; } if (rxbuf) { rxbuf++; } } #endif /* SBBI0_SCK_BIT */ }
/* * Toggles out a single byte in master mode. * * Entry: SCL low, SDA any * Exit: SCL low, SDA high * * Change SDA only when SCL is low! * Sample SDA short before setting SCL low! */ static int TwPut(GPIO_TWICB* icb, uint8_t octet) { int i; for (i = 0x80; i; i >>= 1) { /* Set the data bit. */ if (octet & i) { I2C_SDA_HI(); } else { I2C_SDA_LO(); } /* Wait for data to stabilize. */ NutMicroDelay (2 * icb->delay_unit); /* Toggle the clock. */ I2C_SCL_HI(); NutMicroDelay (2 * icb->delay_unit); while(I2C_SCL_GET() == 0) { /* Clock stretching*/ NutMicroDelay (2 * icb->delay_unit); } I2C_SCL_LO(); } /* Release data line to receive the ACK bit. */ I2C_SDA_HI(); NutMicroDelay (2 * icb->delay_unit); I2C_SCL_HI(); NutMicroDelay (2 * icb->delay_unit); if (I2C_SDA_GET()) { i = -1; } else { i = 0; } I2C_SCL_LO(); NutMicroDelay (2 * icb->delay_unit); return i; }
static int LcdInit(NUTDEVICE * dev) { #if defined(PMC_PCER) outr(PMC_PCER, _BV(LCD_RS_PIO_ID) | _BV(LCD_EN_PIO_ID)); #endif /* Initialize GPIO lines. */ #ifdef LCD_RW_BIT outr(PMC_PCER, _BV(LCD_RW_PIO_ID)); LCD_RW_CLR(); #endif #ifdef LCD_EN2_BIT outr(PMC_PCER, _BV(LCD_EN2_PIO_ID)); LCD_EN2_CLR(); #endif #ifdef LCD_RST_BIT outr(PMC_PCER, _BV(LCD_RST_PIO_ID)); LCD_RST_CLR(); #endif LCD_RS_CLR(); LCD_RW_CLR(); LcdClrBits(LCD_DATA); NutMicroDelay(30); LCD_EN_CLR(); NutMicroDelay(30); /* Initial delay. Actually only required after power on. */ NutSleep(16); /* This initialization will make sure, that the LCD is switched * to 8-bit mode, no matter which mode we start from or we finally * need. */ LcdWriteNibble((_BV(LCD_FUNCTION) | _BV(LCD_FUNCTION_8BIT)) >> 4); NutSleep(15); LcdWriteNibble((_BV(LCD_FUNCTION) | _BV(LCD_FUNCTION_8BIT)) >> 4); NutSleep(4); LcdWriteNibble((_BV(LCD_FUNCTION) | _BV(LCD_FUNCTION_8BIT)) >> 4); NutSleep(2); #ifdef LCD_IF_4BIT /* We now switch to 4-bit mode */ LcdWriteNibble(_BV(LCD_FUNCTION) >> 4); NutSleep(2); // TODO: Add support for large font in single line displays /* Set number of lines and font. Can't be changed later. */ #if (LCD_ROWS == 2) || (LCD_ROWS==4) LcdWriteNibble((_BV(LCD_FUNCTION) | _BV(LCD_FUNCTION_2LINES)) >> 4); LcdWriteNibble(_BV(LCD_FUNCTION) | _BV(LCD_FUNCTION_2LINES)); #else LcdWriteNibble(_BV(LCD_FUNCTION) >> 4); LcdWriteNibble(_BV(LCD_FUNCTION) ); #endif #else /* LCD_IF_4BIT */ LcdWriteCmd(_BV(LCD_FUNCTION) | _BV(LCD_FUNCTION_8BIT)); #endif /* LCD_IF_4BIT */ NutSleep(2); /* Switch display and cursor off. */ LcdWriteNibble(_BV(LCD_ON_CTRL) >> 4); LcdWriteNibble(_BV(LCD_ON_CTRL)); NutSleep(2); /* Clear display. */ LcdClear(); /* Set entry mode. */ LcdWriteCmd(_BV(LCD_ENTRY_MODE) | _BV(LCD_ENTRY_INC)); /* Switch display on. */ LcdWriteCmd(_BV(LCD_ON_CTRL) | _BV(LCD_ON_DISPLAY)); /* Move cursor home. */ LcdCursorHome(); /* Set data address to zero. */ LcdWriteCmd(_BV(LCD_DDRAM)); return 0; }
/*! * \brief Loop for a specified number of milliseconds. * * This call will not release the CPU and will not switch to another * thread. Because of absent thread switching, the delay time is more * exact than with NutSleep(). * * \param ms Delay time in milliseconds, maximum is 255. * * \deprecated New applications should use NutMicroDelay(). */ void NutDelay(uint8_t ms) { NutMicroDelay((uint32_t)ms * 1000); }