Shop OBEX P1 Docs P2 Docs Learn Events
OUTA[26..23] := 0b1011; in Propeller C — Parallax Forums

OUTA[26..23] := 0b1011; in Propeller C

Hello,

i converted an assembler program into C
I was trying to use OUTA[26..23] := 0b1111; to set some bits, but I get error

to many decimal points in number;

I need to set a specific range of pins to a pattern without affecting pins outside the range above or below

like
OUTA ^= 0b101010101010101 << 26;

any help would be helpful

thank you

regards

Jeff

Comments

  • kwinnkwinn Posts: 8,697
    Not a C guru, but I don't think OUTA is a valid C statement. That looks exactly like what Spin uses. Check the C documentation.
  • OUTA |= 0b1111 << 23;

    That will do the same thing in C/C++ as

    OUTA[26..23] := 0b1111

    in Spin.
  • Say you want to write the value 0b1010 into bits 23-26. You'll have to do something like this:
    OUTA = (OUTA & ~(0b1111 << 23) | (0b1010 << 23);
    
    I think there is a function in Simple Libraries that makes this a little easier.
  • If you have an arbitrary value (as opposed to all binary 1s), then you can use this:
    OUTA = ((OUTA & ~(mask)) | (value & mask));
    

    Where "mask" is the bit mask of pins you want to write, and value is the value you want written to the port.

    Example:
    OUTA = 0b00110011;
    
    unsigned int mask = 0b00111100; // Only write bits 2 through 5
    
    // Only bits 2 through 5 matter because of the mask above.
    // This line could just as well be 0b00010100 or 0b00010111 and it wouldn't matter
    unsigned int value = 0b11010100;
    
    OUTA = ((OUTA & ~(mask)) | (value & mask));
    
    // New value of OUTA is 0b010111;
    

    Source
  • David Betz wrote: »
    Say you want to write the value 0b1010 into bits 23-26. You'll have to do something like this:
    OUTA = (OUTA & ~(0b1111 << 23) | (0b1010 << 23);
    
    I think there is a function in Simple Libraries that makes this a little easier.

    Beat me to it :)
  • Typically i use macros or a method to set and clear bits. This way I can reuse them elsewhere in my code.

    Ex:
    This will set bit 23:
    var |= (0x01 << 23); // set

    This will clear bit 23
    var &= ~(0x01 << 23); // clear

    This will toggle a bit each time it is called:
    var ^= 0x01 << 23; // toggle

    These could be placed in a function where you have a start and stop value for a range.

    The Macro way would be to do something like:
    #define BIT_MASK(bit) (1 << (bit))
    #define SET_BIT(value,bit) ((value) |= BIT_MASK(bit))
    #define CLEAR_BIT(value,bit) ((value) &= ~BIT_MASK(bit))
    #define TEST_BIT(value,bit) (((value) & BIT_MASK(bit)) ? 1 : 0)

    However, for a range, you would look at some sort of loop or a function that accepts a range to set or clear or even toggle a bit, or use the other great examples the David's have posted.
  • JonMJonM Posts: 318
    edited 2016-12-30 03:53
    SO, just messing around, this is an example of using the Macros I mentioned previously. This is more of a C++ example but the main bits of can be used with C as well;
    //  Macro example:
    #include <iostream>
    #include <stdint.h>
    #include <iomanip>
    
    #define BIT_MASK(bit)             (0x01 << (bit))
    #define SET_BIT(value,bit)        ((value) |= BIT_MASK(bit))
    #define CLEAR_BIT(value,bit)      ((value) &= ~BIT_MASK(bit))
    #define TEST_BIT(value,bit)       (((value) & BIT_MASK(bit)) ? 1 : 0)
    
    
    using namespace std;
    
    void set_some_bits(uint32_t from_val, uint32_t to_val, uint32_t val)
    {
    	for(uint32_t i = from_val; i <= to_val; i++ )
    	{
    		SET_BIT(val, i );
    		cout << "After set bit " << dec << i << " = " << "0x" << setfill('0') << hex << setw(8) << val << endl;
    	}
    }
    
    int main(){
    	uint32_t OUTA = 0x00020304;
    
    	cout << "This is a test\n";
    	cout << "Original value of OUTA = " << "0x" << setfill('0') << hex << setw(8) << OUTA << endl;
    
    	uint32_t byte1 = SET_BIT(OUTA,25);
    
           cout << "Set bit value 25 = " << "0x" << setfill('0') << hex << setw(8) << byte1 << endl;
           cout << "Clear a bit 25 = " << "0x" << setfill('0') << hex << setw(8) << CLEAR_BIT(OUTA, 25) << endl;
           set_some_bits(23, 26, OUTA);
    
    	return 0;
    }
    

    // This will produce:
    This is a test
    Original value of OUTA = 0x00020304
    Set bit value 25 = 0x02020304
    Clear a bit 25 = 0x00020304
    After set bit 23 = 0x00820304
    After set bit 24 = 0x01820304
    After set bit 25 = 0x03820304
    After set bit 26 = 0x07820304
  • If you're looking for something that's kinda similar to the outa[start..end] = 0b###### format, the simpletools library has set_directions and set_outputs functions. Here is an example from:

    http://learn.parallax.com/tutorials/language/propeller-c/propeller-c-simple-circuits/seven-segment-display
      #include "simpletools.h"
      ...
      set_directions(15, 8, 0b11111111);          // P15...P8 -> output
      set_outputs(15, 8, 0b11100111);             // 0 on 7-segment display
      ...
    
  • If you're looking for something that's kinda similar to the outa[start..end] = 0b###### format, the simpletools library has set_directions and set_outputs functions. Here is an example from:

    http://learn.parallax.com/tutorials/language/propeller-c/propeller-c-simple-circuits/seven-segment-display
      #include "simpletools.h"
      ...
      set_directions(15, 8, 0b11111111);          // P15...P8 -> output
      set_outputs(15, 8, 0b11100111);             // 0 on 7-segment display
      ...
    
    Thanks for posting that Andy. I knew simpletools had a concise way of expressing this.

  • Very slick. And thus why it's called "SimpleTools".

    I'm putting together a Noise Level Indicator project and this might come in handy with outputting the sound levels to a Bar Graph display.
  • One reason I posted naked C code is that I thought you might want to know how it is actually done. The functions that Andy mentioned are implemented using the same techniques that I mentioned of course.
  • JonM wrote: »
    Very slick. And thus why it's called "SimpleTools".

    I'm putting together a Noise Level Indicator project and this might come in handy with outputting the sound levels to a Bar Graph display.

    There's a great example of using PropWare and an MCP3000 (an ADC) to turn the 8 LEDs on a Quickstart board into a bar graph, just as you're looking to do. Long version here, and short version following:
    #include <PropWare/gpio/simpleport.h>
    #include <PropWare/sensor/analog/mcp3xxx.h>
    
    using PropWare::MCP3xxx;
    using PropWare::Port;
    using PropWare::SimplePort;
    using PropWare::SPI;
    
    static const MCP3xxx::PartNumber PART_NUMBER = MCP3xxx::PartNumber::MCP300x;
    static const MCP3xxx::Channel    CHANNEL     = MCP3xxx::Channel::CHANNEL_1;
    
    static const Port::Mask MOSI          = Port::P0;
    static const Port::Mask MISO          = Port::P1;
    static const Port::Mask SCLK          = Port::P2;
    static const Port::Mask CS            = Port::P3;
    static const Port::Mask FIRST_LED_PIN = Port::P16;
    static const int        LED_COUNT     = 8;
    static const uint16_t   DIVISOR       = 1024 / LED_COUNT;
    
    int main () {
        SPI     spi(MOSI, MISO, SCLK);
        MCP3xxx adc(spi, CS, PART_NUMBER);
    
        // Set the Quickstart LEDs for output
        SimplePort scale(FIRST_LED_PIN, LED_COUNT, Port::Dir::OUT);
    
        while (1) {
            const uint16_t data = adc.read(CHANNEL);
    
            // convert the ADC's value (ranging from 0-1023) to a number representing
            // how many LEDs should be lit
            const uint8_t scaledValue = (uint8_t) ((data + DIVISOR / 2 - 1) / DIVISOR);
    
            uint32_t ledOutput = 0;
            for (uint8_t i = 0; i < scaledValue; ++i)
                ledOutput = (ledOutput << 1) | 1;
            scale.write(ledOutput);
        }
    }
    

    And here's a simpler snippet explaining the PropWare::SimplePort object's use:
    #include <PropWare/gpio/simpleport.h>
    
    using PropWare::Port;
    using PropWare::SimplePort;
    
    Port::Mask FIRST_PIN = Port::P16;
    unsigned int PORT_WIDTH = 8;
    ...
    SimplePort debugLEDs(FIRST_PIN, PORT_WIDTH, Pin::Dir::OUT);
    debugLEDs.write(0b01010101);
    ...
    

    This code will set the direction and write alternating 0s and 1s. Just like Simple's set_outputs() function, the shifting is done automagically for you. SimplePort is designed for ports with all pins in consecutive order. Ports with pins in non consecutive order can make use of PropWare::Port.

    Interestingly, my PropWare example is actually 100 bytes smaller than Andy's Simple example (2,364 vs 2,468 when compiled in LMM). Sometimes, C++ does indeed win :)
  • David,

    Nice!

    Not to hijack this discussion but I have a example working with an Arduino board where I have the sound input through an OpAMP which is then sent to the Arduino where the LED range on the Bar Graph is determined by a mapping between the input value and the appropriate LED or LEDs on the Display. This is done without an I/O expander however I do like the idea of using something like a MCP3000 series device to reduce the number of connections.

    I'll have to give this whirl.

    Thanks!
  • DavidZemon wrote: »
    JonM wrote: »
    Very slick. And thus why it's called "SimpleTools".

    I'm putting together a Noise Level Indicator project and this might come in handy with outputting the sound levels to a Bar Graph display.

    There's a great example of using PropWare and an MCP3000 (an ADC) to turn the 8 LEDs on a Quickstart board into a bar graph, just as you're looking to do. Long version here, and short version following:
    #include <PropWare/gpio/simpleport.h>
    #include <PropWare/sensor/analog/mcp3xxx.h>
    
    using PropWare::MCP3xxx;
    using PropWare::Port;
    using PropWare::SimplePort;
    using PropWare::SPI;
    
    static const MCP3xxx::PartNumber PART_NUMBER = MCP3xxx::PartNumber::MCP300x;
    static const MCP3xxx::Channel    CHANNEL     = MCP3xxx::Channel::CHANNEL_1;
    
    static const Port::Mask MOSI          = Port::P0;
    static const Port::Mask MISO          = Port::P1;
    static const Port::Mask SCLK          = Port::P2;
    static const Port::Mask CS            = Port::P3;
    static const Port::Mask FIRST_LED_PIN = Port::P16;
    static const int        LED_COUNT     = 8;
    static const uint16_t   DIVISOR       = 1024 / LED_COUNT;
    
    int main () {
        SPI     spi(MOSI, MISO, SCLK);
        MCP3xxx adc(spi, CS, PART_NUMBER);
    
        // Set the Quickstart LEDs for output
        SimplePort scale(FIRST_LED_PIN, LED_COUNT, Port::Dir::OUT);
    
        while (1) {
            const uint16_t data = adc.read(CHANNEL);
    
            // convert the ADC's value (ranging from 0-1023) to a number representing
            // how many LEDs should be lit
            const uint8_t scaledValue = (uint8_t) ((data + DIVISOR / 2 - 1) / DIVISOR);
    
            uint32_t ledOutput = 0;
            for (uint8_t i = 0; i < scaledValue; ++i)
                ledOutput = (ledOutput << 1) | 1;
            scale.write(ledOutput);
        }
    }
    

    And here's a simpler snippet explaining the PropWare::SimplePort object's use:
    #include <PropWare/gpio/simpleport.h>
    
    using PropWare::Port;
    using PropWare::SimplePort;
    
    Port::Mask FIRST_PIN = Port::P16;
    unsigned int PORT_WIDTH = 8;
    ...
    SimplePort debugLEDs(FIRST_PIN, PORT_WIDTH, Pin::Dir::OUT);
    debugLEDs.write(0b01010101);
    ...
    

    This code will set the direction and write alternating 0s and 1s. Just like Simple's set_outputs() function, the shifting is done automagically for you. SimplePort is designed for ports with all pins in consecutive order. Ports with pins in non consecutive order can make use of PropWare::Port.

    Interestingly, my PropWare example is actually 100 bytes smaller than Andy's Simple example (2,364 vs 2,468 when compiled in LMM). Sometimes, C++ does indeed win :)
    I don't use the C++ "using" keyword much but I thought that using this declaration
    using PropWare::Port;
    
    would allow you to leave out the "Port::" prefix and write code like this:
    static const Mask MOSI          = P0;
    
    Is that not true?


  • David Betz wrote: »
    DavidZemon wrote: »
    JonM wrote: »
    Very slick. And thus why it's called "SimpleTools".

    I'm putting together a Noise Level Indicator project and this might come in handy with outputting the sound levels to a Bar Graph display.

    There's a great example of using PropWare and an MCP3000 (an ADC) to turn the 8 LEDs on a Quickstart board into a bar graph, just as you're looking to do. Long version here, and short version following:
    #include <PropWare/gpio/simpleport.h>
    #include <PropWare/sensor/analog/mcp3xxx.h>
    
    using PropWare::MCP3xxx;
    using PropWare::Port;
    using PropWare::SimplePort;
    using PropWare::SPI;
    
    static const MCP3xxx::PartNumber PART_NUMBER = MCP3xxx::PartNumber::MCP300x;
    static const MCP3xxx::Channel    CHANNEL     = MCP3xxx::Channel::CHANNEL_1;
    
    static const Port::Mask MOSI          = Port::P0;
    static const Port::Mask MISO          = Port::P1;
    static const Port::Mask SCLK          = Port::P2;
    static const Port::Mask CS            = Port::P3;
    static const Port::Mask FIRST_LED_PIN = Port::P16;
    static const int        LED_COUNT     = 8;
    static const uint16_t   DIVISOR       = 1024 / LED_COUNT;
    
    int main () {
        SPI     spi(MOSI, MISO, SCLK);
        MCP3xxx adc(spi, CS, PART_NUMBER);
    
        // Set the Quickstart LEDs for output
        SimplePort scale(FIRST_LED_PIN, LED_COUNT, Port::Dir::OUT);
    
        while (1) {
            const uint16_t data = adc.read(CHANNEL);
    
            // convert the ADC's value (ranging from 0-1023) to a number representing
            // how many LEDs should be lit
            const uint8_t scaledValue = (uint8_t) ((data + DIVISOR / 2 - 1) / DIVISOR);
    
            uint32_t ledOutput = 0;
            for (uint8_t i = 0; i < scaledValue; ++i)
                ledOutput = (ledOutput << 1) | 1;
            scale.write(ledOutput);
        }
    }
    

    And here's a simpler snippet explaining the PropWare::SimplePort object's use:
    #include <PropWare/gpio/simpleport.h>
    
    using PropWare::Port;
    using PropWare::SimplePort;
    
    Port::Mask FIRST_PIN = Port::P16;
    unsigned int PORT_WIDTH = 8;
    ...
    SimplePort debugLEDs(FIRST_PIN, PORT_WIDTH, Pin::Dir::OUT);
    debugLEDs.write(0b01010101);
    ...
    

    This code will set the direction and write alternating 0s and 1s. Just like Simple's set_outputs() function, the shifting is done automagically for you. SimplePort is designed for ports with all pins in consecutive order. Ports with pins in non consecutive order can make use of PropWare::Port.

    Interestingly, my PropWare example is actually 100 bytes smaller than Andy's Simple example (2,364 vs 2,468 when compiled in LMM). Sometimes, C++ does indeed win :)
    I don't use the C++ "using" keyword much but I thought that using this declaration
    using PropWare::Port;
    
    would allow you to leave out the "Port::" prefix and write code like this:
    static const Mask MOSI          = P0;
    
    Is that not true?


    I wish it were true. Unfortunately, it isn't, and you can't use the "using" keyword with enums either (no "using PropWare::Port::Mask") - not even class enums. In fact, I won't swear to it, but I don't think you can even use it with inner classes. Here's the error message that GCC 4.6 throws with "using PropWare::Port::Mask":
    error: 'PropWare::Port' is not a namespace
    
  • Ah, yes. Of course. PropWare::Port is not a namespace so you can't use any names that are defined inside of Port. Thanks for the clarification.
Sign In or Register to comment.