Shop OBEX P1 Docs P2 Docs Learn Events
Cannot ping EEPROM on PPDB — Parallax Forums

Cannot ping EEPROM on PPDB

I'm trying to use the EEPROM on the Propeller Professional Development Board but have not been able to ping it. propeller-load is able to write my program to EEPROM successfully and verify it, so that means the EEPROM chip should be working, right?

The exact same binary is able to ping the EEPROM on my Quickstart board.
#include <PropWare/gpio/pin.h>

using namespace PropWare;

class I2CMaster {
    public:
        static const Pin::Mask    DEFAULT_SCL_MASK  = Pin::Mask::P28;
        static const Pin::Mask    DEFAULT_SDA_MASK  = Pin::Mask::P29;
        static const unsigned int DEFAULT_FREQUENCY = 400000;

    public:
        /**
         * @brief       Create a basic I2C instance
         *
         * @param[in]   sclMask     Pin mask for the SCL pin (default value uses the EEPROM SCL line)
         * @param[in]   sdaMask     Pin mask for the SDA pin (default value uses the EEPROM SDA line)
         * @param[in]   frequency   Frequency to run the bus (default is highest standard I2C frequency of 400 kHz)
         */
        I2CMaster (const Pin::Mask sclMask = DEFAULT_SCL_MASK, const Pin::Mask sdaMask = DEFAULT_SDA_MASK,
                   const unsigned int frequency = DEFAULT_FREQUENCY)
                : m_scl(sclMask, Pin::Dir::IN),
                  m_sda(sdaMask, Pin::Dir::IN) {
            this->set_frequency(frequency);

            //Set outputs low
            this->m_scl.clear();
            this->m_sda.clear();
        }

        /**
         * @brief       Set the bus frequency
         *
         * @param[in]   frequency   Frequency in Hz to run the bus
         */
        void set_frequency (const unsigned int frequency) {
            this->m_clockDelay = CLKFREQ / (frequency << 1);
        }

        /**
         * @brief   Output a start condition on the I2C bus
         */
        void start () const {
            this->half_clock();
            this->m_scl.set();
            this->m_sda.set();
            this->m_scl.set_dir_out();
            this->m_sda.set_dir_out();

            this->half_clock();
            this->m_sda.clear();
            this->half_clock();
            this->m_scl.clear();
        }

        /**
         * @brief   Output a stop condition on the I2C bus
         */
        void stop () const {
            this->m_sda.clear();
            this->m_scl.clear();

            this->half_clock();
            this->m_scl.set_dir_in();
            this->half_clock();
            this->m_sda.set_dir_in();
        }

        /**
         * @brief   Output a byte on the I2C bus.
         *
         * @param[in]   byte    8 bits to send on the bus
         *
         * @return      true if the device acknowledges, false otherwise
         */
        bool send_byte (const uint8_t byte) const {
            int result   = 0;
            int dataMask = 0;
            int nextCnt  = 0;
            int temp     = 0;

            __asm__ volatile(
            FC_START("PutByteStart", "PutByteEnd")
            /* Setup for transmit loop */
            "         mov       %[_dataMask],   #256                \n\t" /* 0x100 */
            "         mov       %[_result],     #0                  \n\t"
            "         mov       %[_nextCnt],    cnt                 \n\t"
            "         add       %[_nextCnt],    %[_clockDelay]      \n\t"

            /* Transmit Loop (8x) */
            //Output bit of byte
            "PutByteLoop%=: "
            "         shr       %[_dataMask],   #1                  \n\t" // Set up mask
            "         and       %[_dataMask],   %[_dataByte] wz,nr  \n\t" // Move the bit into Z flag
            "         muxz      dira,           %[_SDAMask]         \n\t"

            //Pulse clock
            "         waitcnt   %[_nextCnt],    %[_clockDelay]      \n\t"
            "         andn      dira,           %[_SCLMask]         \n\t" // Set SCL high
            "         waitcnt   %[_nextCnt],    %[_clockDelay]      \n\t"
            "         or        dira,           %[_SCLMask]         \n\t" // Set SCL low

            //Return for more bits
            "         djnz      %[_dataMask],   #" FC_ADDR("PutByteLoop%=", "PutByteStart") " nr \n\t"

            // Get ACK
            "         andn      dira,           %[_SDAMask]         \n\t" // Float SDA high (release SDA)
            "         waitcnt   %[_nextCnt],    %[_clockDelay]      \n\t"
            "         andn      dira,           %[_SCLMask]         \n\t" // SCL high (by float)
            "         waitcnt   %[_nextCnt],    %[_clockDelay]      \n\t"
            "         mov       %[_temp],       ina                 \n\t" //Sample input
            "         and       %[_SDAMask],    %[_temp] wz,nr      \n\t" // If != 0, ack'd, else nack
            "         muxz      %[_result],     #1                  \n\t" // Set result to equal to Z flag (aka, 1 if ack'd)
            "         or        dira,           %[_SCLMask]         \n\t" // Set scl low
            "         or        dira,           %[_SDAMask]         \n\t" // Set sda low

            FC_END("PutByteEnd")
            : // Outputs
            [_dataMask] "=&r"(dataMask),
            [_result] "=&r"(result),
            [_nextCnt] "=&r"(nextCnt),
            [_temp] "=&r"(temp)
            : // Inputs
            [_SDAMask] "r"(this->m_sda.get_mask()),
            [_SCLMask] "r"(this->m_scl.get_mask()),
            [_dataByte] "r"(byte),
            [_clockDelay] "r"(m_clockDelay));

            return (bool) result;
        }

        /**
         * @brief   Test for the Acknowledge of a device by sending start and the slave address.
         *
         * Useful for polling the bus and seeing what devices are available. Ping uses the following format:
         *
         *  +--------+----+-------+-----+----+
         *  | Master | ST | SAD+W |     | SP |
         *  | Slave  |    |       | SAK |    |
         *  +--------+----+-------+-----+----+
         *
         * @param[in]   device  7-bit shifted address device (in bits 7-1, not 6-0)
         *
         * @return      true if ack was received, false otherwise
         */
        bool ping (const uint8_t device) const {
            this->start();
            bool result = this->send_byte(device);
            this->stop();
            return result;
        }

    private:

        /**
         * @brief   Wait for half of one clock period, or the minimum waiting period
         *
         * When compiled with the compact memory model (CMM), it is easily possible that half of the waiting period
         * is less time than it takes to execute the waitcnt() function. Therefore, this will either wait for half of
         * the clock's period or a single `nop` instruction may be run if the clock is too fast.
         */
        void half_clock () const {
#ifdef __PROPELLER_CMM__
            if (500 > m_clockDelay)
                __asm__ volatile ("nop;");
            else
                waitcnt(m_clockDelay + CNT);
#else
            waitcnt(this->m_clockDelay + CNT);
#endif
        }

    private:
        const Pin    m_scl;
        const Pin    m_sda;
        unsigned int m_clockDelay;
};

int main () {
    const Pin::Mask LED_PIN_MASK = Pin::Mask::P16;
    const Pin       led(LED_PIN_MASK, Pin::Dir::OUT);
    const I2CMaster i2c;

    bool eepromAck;
    do {
        eepromAck = i2c.ping(0x50 << 1);
        if (!eepromAck) {
            led.toggle();
            waitcnt(CNT + 50 * MILLISECOND);
        }
    } while (!eepromAck);

    while (1) {
        led.toggle();
        waitcnt(CNT + 200 * MILLISECOND);
    }
}

anyone have any idea why it's failing to ping on my PPDB?

Comments

Sign In or Register to comment.