static void delay_us(cyg_int32 usecs) { CYGARC_HAL_SAVE_GP(); #ifdef CYGPKG_KERNEL { cyg_int32 start, elapsed; cyg_int32 usec_ticks, slice; // How many ticks total we should wait for. usec_ticks = usecs*CYGNUM_KERNEL_COUNTERS_RTC_PERIOD; usec_ticks /= CYGNUM_HAL_RTC_NUMERATOR/CYGNUM_HAL_RTC_DENOMINATOR/1000; do { // Spin in slices of 1/2 the RTC period. Allows interrupts // time to run without messing up the algorithm. If we spun // for 1 period (or more) of the RTC, there'd be also problems // figuring out when the timer wrapped. We may lose a tick or // two for each cycle but it shouldn't matter much. slice = usec_ticks % (CYGNUM_KERNEL_COUNTERS_RTC_PERIOD / 2); HAL_CLOCK_READ(&start); do { HAL_CLOCK_READ(&elapsed); elapsed = (elapsed - start); // counts up! if (elapsed < 0) elapsed += CYGNUM_KERNEL_COUNTERS_RTC_PERIOD; } while (elapsed < slice); // Adjust by elapsed, not slice, since an interrupt may have // been stalling us for some time. usec_ticks -= elapsed; } while (usec_ticks > 0); } #else // CYGPKG_KERNEL #ifdef HAL_DELAY_US // Use a HAL feature if defined HAL_DELAY_US(usecs); #else // If no accurate delay mechanism, just spin for a while. Having // an inaccurate delay is much better than no delay at all. The // count of 10 should mean the loop takes something resembling // 1us on most CPUs running between 30-100MHz [depends on how many // instructions this compiles to, how many dispatch units can be // used for the simple loop, actual CPU frequency, etc] while (usecs-- > 0) { int i; for (i = 0; i < 10; i++); } #endif // HAL_DELAY_US #endif // CYGPKG_KERNEL CYGARC_HAL_RESTORE_GP(); }
__externC void hal_delay_us( cyg_int32 us ) { cyg_uint32 t0, t1; HAL_CLOCK_READ( &t0 ); while ( us > 0 ) { HAL_CLOCK_READ( &t1 ); if( t1 < t0 ) us -= (t1 + CYGNUM_HAL_RTC_PERIOD - t0); else us -= t1 - t0; t0 = t1; } }
static long long ns_time(void) { cyg_uint32 off; long long ns, clocks; ns_per_system_clock = 1000000/rtc_resolution[1]; HAL_CLOCK_READ(&off); ns = (ns_per_system_clock * (long long)off) / CYGNUM_KERNEL_COUNTERS_RTC_PERIOD; ns += 5; // for rounding to .01us clocks = (cyg_current_time() * 10000000) + ns; return clocks; }
static void delay_us(cyg_int32 usecs) { CYGARC_HAL_SAVE_GP(); #if defined(CYGPKG_KERNEL) && defined(HAL_CLOCK_READ) { cyg_uint32 start, elapsed_hal; cyg_int32 elapsed, elapsed_usec; cyg_int32 slice; cyg_int32 usec_per_period = CYGNUM_HAL_RTC_NUMERATOR/CYGNUM_HAL_RTC_DENOMINATOR/1000; cyg_int32 ticks_per_usec = CYGNUM_KERNEL_COUNTERS_RTC_PERIOD/usec_per_period; do { // Spin in slices of 1/2 the RTC period. Allows interrupts // time to run without messing up the algorithm. If we // spun for 1 period (or more) of the RTC, there would also // be problems figuring out when the timer wrapped. We // may lose a tick or two for each cycle but it shouldn't // matter much. // The tests against CYGNUM_KERNEL_COUNTERS_RTC_PERIOD // check for a value that would cause a 32 bit signed // multiply to overflow. But this also implies that just // multiplying by ticks_per_usec will yield a good // approximation. Otherwise we need to do the full // multiply+divide to get sufficient accuracy. Note that // this test is actually constant, so the compiler will // eliminate it and only compile the branch that is // selected. if( usecs > usec_per_period/2 ) slice = CYGNUM_KERNEL_COUNTERS_RTC_PERIOD/2; else if( CYGNUM_KERNEL_COUNTERS_RTC_PERIOD/2 >= 0x7FFFFFFF/usec_per_period ) slice = usecs * ticks_per_usec; else { slice = usecs*CYGNUM_KERNEL_COUNTERS_RTC_PERIOD; slice /= usec_per_period; } HAL_CLOCK_READ(&start); do { HAL_CLOCK_READ(&elapsed_hal); elapsed = (elapsed_hal - start); // counts up! if (elapsed < 0) elapsed += CYGNUM_KERNEL_COUNTERS_RTC_PERIOD; } while (elapsed < slice); // Adjust by elapsed, not slice, since an interrupt may // have been stalling us for some time. if( CYGNUM_KERNEL_COUNTERS_RTC_PERIOD >= 0x7FFFFFFF/usec_per_period ) elapsed_usec = elapsed / ticks_per_usec; else { elapsed_usec = elapsed * usec_per_period; elapsed_usec = elapsed_usec / CYGNUM_KERNEL_COUNTERS_RTC_PERIOD; } // It is possible for elapsed_usec to end up zero in some // circumstances and we could end up looping indefinitely. // Avoid that by ensuring that we always decrement usec by // at least 1 each time. usecs -= elapsed_usec ? elapsed_usec : 1; } while (usecs > 0); } #else // CYGPKG_KERNEL #ifdef HAL_DELAY_US // Use a HAL feature if defined HAL_DELAY_US(usecs); #else // If no accurate delay mechanism, just spin for a while. Having // an inaccurate delay is much better than no delay at all. The // count of 10 should mean the loop takes something resembling // 1us on most CPUs running between 30-100MHz [depends on how many // instructions this compiles to, how many dispatch units can be // used for the simple loop, actual CPU frequency, etc] while (usecs-- > 0) { int i; for (i = 0; i < 10; i++); } #endif // HAL_DELAY_US #endif // CYGPKG_KERNEL CYGARC_HAL_RESTORE_GP(); }
static void serial_rcv_char(serial_channel *chan, unsigned char c) { cbuf_t *cbuf = &chan->in_cbuf; #ifdef CYGPKG_NET_BLUEZ_STACK if(chan->receive)//clyu { extern unsigned char bluetooth_buf[]; int len = 0; struct tty_ldisc *ldisc = chan->tty_ldisc; if(ldisc && ldisc->receive_buf && cbuf->nb) { diag_printf("bluetooth\n"); if(cbuf->put < cbuf->get) { memcpy(bluetooth_buf, cbuf->data + cbuf->get, cbuf->len - cbuf->get); len = cbuf->len - cbuf->get; //ldisc->receive_buf(serial_driver, cbuf->data + cbuf->get, (char*)cbuf, cbuf->len - cbuf->get); cbuf->nb -= len; cbuf->get = 0; } memcpy(bluetooth_buf + len, cbuf->data + cbuf->get, cbuf->put); len += cbuf->put; cbuf->get = cbuf->put; cbuf->nb -= len; //ldisc->receive_buf(serial_driver, cbuf->data + cbuf->get, (char*)cbuf, cbuf->nb); ldisc->receive_buf(serial_driver, bluetooth_buf, (char*)cbuf, len); } chan->receive = 0; return; } #endif #if CYGINT_IO_SERIAL_BLOCK_TRANSFER CYG_ASSERT(false == cbuf->block_mode_xfer_running, "Attempting char rcv while block transfer is running"); #endif #ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_SOFTWARE // for software flow control, if the driver returns one of the characters // we act on it and then drop it (the app must not see it) if ( chan->config.flags & CYGNUM_SERIAL_FLOW_XONXOFF_TX ) { if ( c == CYGDAT_IO_SERIAL_FLOW_CONTROL_XOFF_CHAR ) { throttle_tx( chan ); return; // it wasn't a "real" character } else if ( c == CYGDAT_IO_SERIAL_FLOW_CONTROL_XON_CHAR ) { restart_tx( chan ); return; // it wasn't a "real" character } } #endif #ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL // If we've hit the high water mark, tell the other side to stop if ( cbuf->nb >= cbuf->high_water ) { throttle_rx( chan, false ); } #endif #ifdef CYGPKG_IO_SERIAL_SELECT_SUPPORT // Wake up any pending selectors if we are about to // put some data into a previously empty buffer. if( cbuf->nb == 0 ) cyg_selwakeup( &cbuf->selinfo ); #endif // If the flow control is not enabled/sufficient and the buffer is // already full, just throw new characters away. if ( cbuf->nb < cbuf->len ) { cbuf->data[cbuf->put++] = c; if (cbuf->put == cbuf->len) cbuf->put = 0; cbuf->nb++; } // note trailing else #ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS else { // Overrun. Report the error. cyg_serial_line_status_t stat; stat.which = CYGNUM_SERIAL_STATUS_OVERRUNERR; serial_indicate_status(chan, &stat); } #endif if (cbuf->waiting) { #ifdef XX_CYGDBG_DIAG_BUF extern int enable_diag_uart; int _enable = enable_diag_uart; int _time, _stime; externC cyg_tick_count_t cyg_current_time(void); enable_diag_uart = 0; HAL_CLOCK_READ(&_time); _stime = (int)cyg_current_time(); diag_printf("Signal reader - time: %x.%x\n", _stime, _time); enable_diag_uart = _enable; #endif // CYGDBG_DIAG_BUF cbuf->waiting = false; cyg_drv_cond_signal(&cbuf->wait); } }
static Cyg_ErrNo serial_read(cyg_io_handle_t handle, void *_buf, cyg_uint32 *len) { cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle; serial_channel *chan = (serial_channel *)t->priv; serial_funs *funs = chan->funs; cyg_uint8 *buf = (cyg_uint8 *)_buf; cyg_int32 size = 0; cbuf_t *cbuf = &chan->in_cbuf; Cyg_ErrNo res = ENOERR; #ifdef XX_CYGDBG_DIAG_BUF extern int enable_diag_uart; int _enable = enable_diag_uart; int _time, _stime; externC cyg_tick_count_t cyg_current_time(void); #endif // CYGDBG_DIAG_BUF cyg_drv_mutex_lock(&cbuf->lock); cbuf->abort = false; if (cbuf->len == 0) { // Non interrupt driven (i.e. polled) operation while (size++ < *len) { cyg_uint8 c = (funs->getc)(chan); #ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_SOFTWARE // for software flow control, if the driver returns one of the // characters we act on it and then drop it (the app must not // see it) if ( chan->config.flags & CYGNUM_SERIAL_FLOW_XONXOFF_TX ) { if ( c == CYGDAT_IO_SERIAL_FLOW_CONTROL_XOFF_CHAR ) { throttle_tx( chan ); } else if ( c == CYGDAT_IO_SERIAL_FLOW_CONTROL_XON_CHAR ) { restart_tx( chan ); } else *buf++ = c; } else *buf++ = c; #else *buf++ = c; #endif } } else { cyg_drv_dsr_lock(); // Avoid races while (size < *len) { if (cbuf->nb > 0) { #ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL if ( (cbuf->nb <= cbuf->low_water) && (chan->flow_desc.flags & CYG_SERIAL_FLOW_IN_THROTTLED) ) restart_rx( chan, false ); #endif *buf++ = cbuf->data[cbuf->get]; if (++cbuf->get == cbuf->len) cbuf->get = 0; cbuf->nb--; size++; } else { #ifdef CYGOPT_IO_SERIAL_SUPPORT_NONBLOCKING if (!cbuf->blocking) { *len = size; // characters actually read res = -EAGAIN; break; } #endif // CYGOPT_IO_SERIAL_SUPPORT_NONBLOCKING cbuf->waiting = true; #ifdef XX_CYGDBG_DIAG_BUF enable_diag_uart = 0; HAL_CLOCK_READ(&_time); _stime = (int)cyg_current_time(); diag_printf("READ wait - get: %d, put: %d, time: %x.%x\n", cbuf->get, cbuf->put, _stime, _time); enable_diag_uart = _enable; #endif // CYGDBG_DIAG_BUF if( !cyg_drv_cond_wait(&cbuf->wait) ) cbuf->abort = true; #ifdef XX_CYGDBG_DIAG_BUF enable_diag_uart = 0; HAL_CLOCK_READ(&_time); _stime = (int)cyg_current_time(); diag_printf("READ continue - get: %d, put: %d, time: %x.%x\n", cbuf->get, cbuf->put, _stime, _time); enable_diag_uart = _enable; #endif // CYGDBG_DIAG_BUF if (cbuf->abort) { // Give up! *len = size; // characters actually read cbuf->abort = false; cbuf->waiting = false; res = -EINTR; break; } } } cyg_drv_dsr_unlock(); } #ifdef XX_CYGDBG_DIAG_BUF cyg_drv_isr_lock(); enable_diag_uart = 0; HAL_CLOCK_READ(&_time); _stime = (int)cyg_current_time(); diag_printf("READ done - size: %d, len: %d, time: %x.%x\n", size, *len, _stime, _time); enable_diag_uart = _enable; cyg_drv_isr_unlock(); #endif // CYGDBG_DIAG_BUF cyg_drv_mutex_unlock(&cbuf->lock); return res; }
static int start( void ) { // We'll mess about with these interrupt sources: // 13 : EX_IRQ13 from expansion board, active HIGH // 12 : EX_IRQ12 from expansion board, active LOW // 4 : EX_IRQ4 from expansion board, active LOW // 3 : EX_IRQ3 from expansion board, active HIGH int i, hipri; for ( i = 1; i < 16; i++ ) { HAL_INTERRUPT_QUERY_INFO( i, levels[i], ups[i], hipri, masks[i], reqs[i]); } CYG_TEST_CHECK( 0 != masks[13], "Int 13 unmasked initially" ); CYG_TEST_CHECK( 0 != masks[12], "Int 12 unmasked initially" ); CYG_TEST_CHECK( 0 != masks[ 4], "Int 4 unmasked initially" ); CYG_TEST_CHECK( 0 != masks[ 3], "Int 3 unmasked initially" ); CYG_TEST_CHECK( 0 == reqs[13], "Int 13 requests initially" ); CYG_TEST_CHECK( 0 == reqs[12], "Int 12 requests initially" ); CYG_TEST_CHECK( 0 == reqs[ 4], "Int 4 requests initially" ); CYG_TEST_CHECK( 0 == reqs[ 3], "Int 3 requests initially" ); CYG_TEST_CHECK( 0 != levels[13], "Int 13 edgetrig initially" ); CYG_TEST_CHECK( 0 != levels[12], "Int 12 edgetrig initially" ); CYG_TEST_CHECK( 0 != levels[ 4], "Int 4 edgetrig initially" ); CYG_TEST_CHECK( 0 != levels[ 3], "Int 3 edgetrig initially" ); CYG_TEST_CHECK( 0 != ups[13], "Int 13 not up initially" ); CYG_TEST_CHECK( 0 == ups[12], "Int 12 is up initially" ); CYG_TEST_CHECK( 0 == ups[ 4], "Int 4 is up initially" ); CYG_TEST_CHECK( 0 != ups[ 3], "Int 3 not up initially" ); checkallbut( 0 ); // don't exclude any of them // I want to run this loop for 100 centiSeconds, so that 100 clock // interrupts have occurred whilst interfering with the other interrupt // state, to provoke possible problems with interactions there. On a // 100MHz 86832 with default configuration, this usually gives 1200 // loops in total, 12 per centiSecond. But with config variance and // caching behaviour, it's quite possible for this loop to take much // longer, if it takes over 1/2 a centiSecond, aliasing effects could // cause the timing to fail completely, causing test timeouts. Hence // the additional loop limit of 20 times round the inner loop, aiming // for a maximum elapsed time of 20 S maximum, plus extra chances to // break out part way through the loop if a tick has passed. hipri = 0; CYG_TEST_INFO( "About to configure interrupts" ); for ( i = 0; i < 100; i++ ) { int t1, t2, j; HAL_CLOCK_READ( &t1 ); // Do this while/until there is a clock tick // ie. some interrupt activity: for ( j = 0; j < 20; j++ ) { t2 = t1; hipri++; interferewith( 13, 1 ); interferewith( 3, 1 ); interferewith( 4, 0 ); HAL_CLOCK_READ( &t1 ); if ( t1 < t2 ) break; // clock has wrapped t2 = t1; interferewith( 12, 0 ); interferewith( 3, 1 ); interferewith( 3, 1 ); HAL_CLOCK_READ( &t1 ); if ( t1 < t2 ) break; // clock has wrapped t2 = t1; interferewith( 4, 0 ); interferewith( 13, 1 ); interferewith( 12, 0 ); interferewith( 12, 0 ); HAL_CLOCK_READ( &t1 ); if ( t1 < t2 ) break; // clock has wrapped } } CYG_TEST_PASS( "Configured interrupts 3,4,12 & 13 a great deal" ); return hipri; }