// ----------------------------------------------------------------------------------------
//
//  avr/device/spinwait.cpp
//    
//  Bob Cook Development, Robotics Library
//  http://www.bobcookdev.com/rl/
//    
//  This file provides spin-wait delay routines for the Atmel AVR processor family.
//
//  Copyright (C) 2007 Bob Cook
//
//      This program is free software; you can redistribute it and/or modify it
//      under the terms of the GNU General Public License as published by the
//      Free Software Foundation; either version 2 of the License, or (at your
//      option) any later version.
//    
//      This program is distributed in the hope that it will be useful, but 
//      WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
//      or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License 
//      for more details.
//    
//      You should have received a copy of the GNU General Public License along
//      with this program; if not, write to the Free Software Foundation, Inc., 
//      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
//
// ----------------------------------------------------------------------------------------


#include "spinwait.h"


// ----------------------------------------------------------------------------------------

#include "project_defs.h"


// ----------------------------------------------------------------------------------------

#if !defined( PRJ_CPU_FREQ )
#error undefined value PRJ_CPU_FREQ
#endif


// ----------------------------------------------------------------------------------------

void spinwait_delay_us( uint16_t microseconds )
{
    register uint16_t loop_count;

    // each loop requires 4 instructions, so there is a fixed number of loops required
    // to delay one microsecond but this varies by clock speed.

#if ( PRJ_CPU_FREQ == 1000000 )
    
    // 1mhz clock
    loop_count = microseconds / 4;

#elif ( PRJ_CPU_FREQ == 2000000 )
    
    // 2mhz clock
    loop_count = microseconds / 2;

#elif ( PRJ_CPU_FREQ == 4000000 )
    
    // 4mhz clock
    loop_count = microseconds;

#elif ( PRJ_CPU_FREQ == 8000000 )
    
    // 8mhz clock
    loop_count = microseconds * 2;

#elif ( PRJ_CPU_FREQ == 16000000 )

    // 16mhz clock
    loop_count = microseconds * 4;

#elif ( PRJ_CPU_FREQ == 20000000 )
    
    // 20mhz clock
    loop_count = microseconds * 5;

#else
#error PRJ_CPU_FREQ unrecognized setting!
#endif

    __asm__ volatile (
        "1: sbiw %0,1" "\n\t"
        "brne 1b"
        : "=w" ( loop_count )
        : "0"  ( loop_count )
    );
}


// ----------------------------------------------------------------------------------------

void spinwait_delay_ms( uint16_t milliseconds )
{
    uint16_t i;

    for ( i = 0; i < milliseconds; ++i )
    {
        spinwait_delay_us( 1000 );
    }
}


// ----------------------------------------------------------------------------------------
//  end of spinwait.cpp
// ----------------------------------------------------------------------------------------

