I'm now doing a project in CCS (Code Composer Studio) with the device CC1310.
I think is good to mention that I'm relatively new to CCS.
I have a hard time finding a simple way to read the analog value form the PINS on the board. (similar to Arduino: int x = analogRead(A1) )
Question: How do I store and read analog values from the Pins on the board?
I thankful for all answers
Kind Regards // Troubled Engineering Student
The ADC header file should be included in an application as follow
#include <ti/drivers/ADC.h>
Operation
The ADC driver operates as a simplified ADC module with only single channel sampling support. It also operates on blocking only mode which means users have to wait the current sampling finished before starting another sampling. The sampling channel needs to be specified in the ADC_open() before calling ADC_convert().
The APIs in this driver serve as an interface to a typical TI-RTOS application. The specific peripheral implementations are responsible to create all the SYS/BIOS specific primitives to allow for thread-safe operation. User can use the ADC driver or the ADCBuf driver that has more features. But both ADC and ADCBuf cannot be used together in an application.
Opening the driver
ADC_Handle adc;
ADC_Params params;
ADC_Params_init(¶ms);
adc = ADC_open(Board_ADCCHANNEL_A1, ¶ms);
if (adc == NULL) {
// ADC_open() failed
while (1);
}
Converting
An ADC conversion with a ADC peripheral is started by calling ADC_convert(). The result value is returned by ADC_convert() once the conversion is finished
int_fast16_t res;
uint_fast16_t adcValue;
res = ADC_convert(adc, &adcValue);
if (res == ADC_STATUS_SUCCESS) {
//use adcValue
}
If you're asking about digital I/O (on or off) then the term you should research in the MCU's Datasheet and Technical Reference Manual is "GPIO". If you have a development kit (such as a LaunchPad) then study the GPIO example that is provided with the development kit's SDK. The SDK probably includes a peripheral driver library that provides a higher level interface to the GPIO peripheral. If so then you could link your application with the library and use the library API to set/get the GPIO data values. Or if you want to do it at the lowest level then you'll need to study the memory-mapped interface to the GPIO registers, which is described in the Technical Reference Manual. For example, the DIN31_0 register is used to read the GPIO input values.
You can find links to everything I mentioned at http://www.ti.com/product/CC1310
Related
I've been working on a project where I use a PGA2310 volume control IC to set the volume of an audio signal. The chip's interface is supposedly SPI, but no matter how much I try, I just can't seem to get it right. The chip takes a 16 bit word over SPI that contains the left and right channel volume information.
I'm wondering if I am using the sdk all wrong and my code is whacked.
I guess my question is: Am I setting up and using the SPI functions correctly?
Here is my code
/**
* SPI interface for PGA2310 volume control ic
*/
#include "pico/stdlib.h"
#include "hardware/spi.h"
#include "pico/time.h"
const int CS = 0;
const int SDI = 1;
const int SCLK = 2;
const int LED_PIN16 = 16;
const int LED_PIN25 = 25;
uint16_t PGA2310();
uint16_t PGA2310() {
int baud = 1600000;
// SPI inistalization
spi_init(spi0, baud);
spi_set_format(spi0, 16, SPI_CPOL_0 , SPI_CPHA_0, SPI_MSB_FIRST);
// Sets SPI pins
gpio_set_function(CS, GPIO_FUNC_SPI);
gpio_set_function(SDI, GPIO_FUNC_SPI);
gpio_set_function(SCLK, GPIO_FUNC_SPI);
// Sets LED pins
gpio_init(LED_PIN16);
gpio_set_dir(LED_PIN16, GPIO_OUT);
gpio_init(LED_PIN25);
gpio_set_dir(LED_PIN25, GPIO_OUT);
// Data to send to chip. only sending first 8 bits for right channel.
// This is because I am currently just testing the output of the right channel
uint16_t high = 255;
uint16_t low = 100;
// Test by toggling between high and low volume states with LED indicators
while (true) {
gpio_put(LED_PIN25, 1);
spi_write16_blocking(spi0, &high, 1);
sleep_ms(2000);
gpio_put(LED_PIN25, 0);
spi_write16_blocking(spi0, &low, 1);
sleep_ms(2000);
}
}
I've tried a bunch of different methods that I found online for using SPI with the pico SDK. I've tried just sending 8 bits.
Let me know if more info is needed.
As explained in comments, SPI normally consists of 4 signals: /SS, SCLK, MOSI and MISO.
/SS = slave select, also known as chip select. Almost always active low.
SCLK = serial clock.
MOSI = Master Output Slave Input. The main data line. Your MCU seems to call this SDO (serial data out?).
MISO = Master Input Slave Output. Optional signal for duplex (two way) communication SPI. Your MCU seems to call this SDI (serial data input).
In this case the MCU is the master so you should be using MOSI/SDO. A MCU is almost always the master, except when communicating with other MCUs.
Additionally, always double check which CPOL and CPHA settings that the slave expects. Getting these wrong is a classic problem and can lead to subtle "clock skew" problems where everything works fine most of the time, then fail and give corrupt data intermittently.
The names you pick for variables/constants in C code do not have any effect on the hardware and they disappear as soon as the code is compiled. The most important thing is that you understand how the hardware works, read the documentation for the RP2040 SDK functions you are calling, and then pass the correct values to the RP2040 SDK functions.
The biggest problem is that you need to rethink every pin assignment. The RP2040 hardware SPI pin functions are defined in column F1 of the "GPIO Functions" section of the RP2040 datasheet. Here is an excerpt from that table:
This table tells us, for example, you cannot use pin 0 as the SPI0 CS function. If you assign that pin to be an SPI pin, it will be the SPI0 RX (data receiving) pin.
At a minimum, you need to pick one pin to be the SPI0 SCK pin and another to be the SPI0 TX pin, and you must connect those pins from the RP2040 to the equivalent pins on your device. Then you might also need to pick an RP2040 pin to control the CS pin on your device, if it has one. On the RP2040 side, this pin would be configured as a GPIO output pin and you would drive it low or high to enable your device. Refer to your device's datasheet for details about what signals it expects on its inputs and then use an oscilloscope to make sure you are generating compliant signals.
Another problem is that the spi_write16_blocking is probably modifying your high and low variables, so you will probably need to set those to the right values before each time that you use them. (So there is no point in having two different variables like that, just have one.)
I'm trying to play a note through the speaker of my board. Currently, I have an interrupt as follows:
void sampleISR(void) {
static uint32_t phaseAcc = 0;
phaseAcc += a; //this `a` is modified outside
analogWrite(OUTR_PIN, phaseAcc);
}
It is attached in the setup() function as follows:
TIM_TypeDef *Instance = TIM1;
HardwareTimer *sampleTimer = new HardwareTimer(Instance);
sampleTimer->setOverflow(22000, HERTZ_FORMAT);
sampleTimer->attachInterrupt(sampleISR);
sampleTimer->resume();
I am trying to use a DMA to reduce the strain on my CPU and also increase the sampling rate (making the 22000 bigger). I am trying to use this as my board supports it, however, I am conceptually confused as to what the transformation entails. Currently, I have an interrupt which modifies the analogWrite value to pin OUTR_PIN every 22000 samples. My current understanding is that a DMA is a tool that connects memory to peripherals or memory to memory, in such a way that data can be transferred without the need for the CPU to do it. However, I am uncertain as to what that means in the current context. Would I need to create a memory-to-periphery DMA where the source is memory (my phaseAcc variable and the output is a periphery (my OUTR_PIN?). I am not sure how I would go around doing this, or if what I described above is correct. I am trying to directly mimic the functionality described above.
I am using a board from the stm32 family.
To drive a speaker you normally use the DAC (digital to analog converter) with a PWM signal (pulse width modulation) On STM32 the DAC / PWM can be linked with DMA (Direct Memory Access), see i.e. HAL_TIM_PWM_Start_DMA from the HAL library, in https://deepbluembedded.com/stm32-dac-sine-wave-generation-stm32-dac-dma-timer-example/ and https://community.st.com/s/question/0D50X0000AAJMUVSQ5/start-pwm-with-dma-haltimpwmstartdma-results-in-hardfault is example code, however you should not drive a speaker with a pure sine wave
For details see also this Application Note : https://www.st.com/resource/en/application_note/cd00259245-audio-and-waveform-generation-using-the-dac-in-stm32-products-stmicroelectronics.pdf
To generate a desired waveform you have to adapt the waveform lookup table described in https://deepbluembedded.com/stm32-dac-sine-wave-generation-stm32-dac-dma-timer-example/
I have developed a custom STM32L475 board with one GPIO pin wired up for synchronization along some other circuitry for the synchronization, unfortunately we decided to route the generated sinus signal from module to module.
This is not optimal so I want to optimize so it is not the sinus signal which is routed from master module to slave modules, but to just transfer a digital trigger to restart the generation of a full sine wave.
To do this I need to be able to setup the MCU's to use the one GPIO pin on each MCU as both output and trigger for a timer.
To do this without an update of the HW I need to be able to combine:
1. Using the 3 pins (one from each MCU) as open drain outputs as an AND gate, this works.
2. I know the GPIO pin can be used as external trigger, triggering on a negative edge.
The question is, is it possible to trig a timer of an output pin using only one GPIO pin, to make the MCU which finalizes its sine generation first trigger itself and the other MCU's, and if so, how?
Please note, it must use the level of the output pin itself, eventhough it is an outputpin.
I am a HW developer, learning to do firmware for our HW, so I am kind of new to software development, so I am using HAL, please be nice
STM32L475 allows to configure a GPIO in different modes that must be (exclusively) selected through the corresponding GPIOx_MODER register:1
(Digital) Input mode
General purpose output mode
Alternate function mode
Analog mode
The alternate function applied in Alternate function mode must also be selected exclusively, through the corresponding GPIOx_AFRL or GPIOx_AFRH register, resp.2
The trigger for an interrupt or timer is an alternate function, and the output of a (analogue or digital) signal is a (different) alternate function, too.
Therefore, I think there is no solution to the given problem based on peripheral configuration.
1
Reference Manual, Rev 7:
See
Section 8.5.1 for GPIO mode selection
Figures 23/24 in Section 8.4 for explanation
2
ibid.:
See
Section 8.5.9 for GPIO alternate function selection
Section 8.4.2 for explanation
I have an STM32L051 and want to drive an external DAC (SPI).
For that I would like to use the feature, mentioned in the manual, to output the internal reference voltage to the PB1 pin of the STM32.
I use the STM32Cube HAL as a basis. However the examples of using the VREF are limited to internal use for ADCs and comparators.
If I understand correctly, I can use the CFGR3 register to both enable the VREF as well as connect it to the PB1. Using the Cube drivers, I can use the HAL_SYSCFG_VREFINT_OutputSelect(SYSCFG_VREFINT_OUT_PB1) function, but to enable it, I should use either HAL_ADCEx_EnableVREFINT() or HAL_COMPEx_EnableVREFINT(). The manual information on SEL_VREF_OUT indicates that ENBUF_VREFINT_ADC must be set.
Furthermore no mention is made about the configuration of the pin itself. Should I simply declare it as a DAC Pin? An ADC Pin?
Answer
It is as simple as
if ( HALD_ADCEx_EnableVREFINT() != HAL_OK )
{
Error_Handling();
}
HAL_SYSCFG_VREFINT_OutputSelect(SYSCFG_VREFINT_OUT_PB1);
And I can see the 1.22 V on the PB1 output.
It does not require further pin (GPIO) configuration.
Complications and justification for the question (can be skipped)
I had some issues with the board from out electronic dept. and thus switched to the STM32L053-Discovery board. The above solution did not work, and I kept seeing 0V on PB1 (or PB0).
I assumed that was due to some configuration missing. However, after some further tests, I actually found that on that Discovery board, both PB1 and PB0 are reserved for a sensor. By closing the SB23 bridge, I could use PB1 back to the GPIO, and thus see the reference voltage on the pin.
I knew there is a similar post:
Steps to make a LED blink from a C/C++ program?
But now I am working on a arm-based development board, and it seems to have two serial ports that I could use it to make a LED on or off.
Basically I think the flow is , make one pin in serial "1" or on and the LED will be turned on and "0" to make it off.
Is there some reference code in C-language I could refers?
Generally speaking, the board should come with some Board Support Package (BSP) which lets you control the built in I/O. Look for a serial library if you really want to use the Hardware flow control signals.
I'd recommend looking for some GPIO (General Purpose I/O, or digial I/O) on the board, which typically lets you configure it as an input or an output. You should be able to connect the LED via a current limiting resister between a digital I/O line and a ground pin. Make sure you have the LED oriented correctly if you connect it backwards it will block the current instead lighting. And as always make sure you check it out with a digital voltage meter before connecting it.
Even if you don't have a BSP for digital I/O the configuration is usually pretty simple.
Set a bit in a register to enable it, set bit in another register to select input or output they will normally be arranged in 8-bit "ports." Some systems allow you configure individual I/O pins, other will only allow you to configure the whole port for input or output. Then you just write a 1 or 0 to the bit you want to control in an write/output register.
ARM chips typically have a considerable amount of built in peripherals today, so most boards will just be bringing the I/O out to physical connectors on the board and you may need to read the chip vender's documentation to find the register memory map. Better board venders will supply documentation, a library (BSP) and examples. Luminary Micro even supplies chips with built in ethernet MACs and PHYs, just add a connector and Magnetics and you have a 1 chip Webserver.
This will, I'm afraid, be heavily dependent on the specifications of the particular arm-based development board you are using.
You need to find documentation specific to that board.
I used to do this kind of programming before.
You need to study the serial port connection
http://www.lammertbies.nl/comm/cable/RS-232.html
http://www.beyondlogic.org/serial/serial.htm
It has +5v, -5v on the output, I can't remember clearly now. Not every pin is needed.
I never use ARM before, but I use a 8-bit PIC controller to program it. I guess you can find a lot of example online.
The preferred alternative for controlling a GPIO is via a BSP. Because this BSP (board support package) does all the work for you in setting all peripherals to good defaults and and allowing you to call a function. Possibly your BSP of choice will have a function to write a byte to an 8-bit GPIO port; your LED will only have one bit. In this case your C code could look like: (at least: it will work like this on Luminary Micro kits). (Example code; requires a bit of extra work to make it compile especially on your kit).
/* each LED is addressed by an address (byte) and a bit-within-this-byte */
struct {
address, // address of IO register for LED port
bit // bit of LED
} LEDConfigPair;
struct LEDConfigPair LEDConfig[NUMBER_OF_LEDS] = {
{GPIO_PORTB_BASE,0}, // LED_0 is at port B0
{GPIO_PORTB_BASE,1} // LED_1 is at port B1
} ;
/* function LED_init configures the GPIOs where LEDs are connected as output */
led_init(void)
{
U32 i;
for(i=0;i<NUMBER_OF_LEDS;i++)
{
GPIODirModeSet( LEDConfig[i][0], LEDConfig[i][1], GPIO_DIR_MODE_OUT );
}
}
/* my LED function
set_led_state makes use of the BSP of Luminary Micro to access a GPIO function
Implementation: this BSP requires setting 8 port wide IO, so the function will calculate a mask (
*/
set_led_state(U8 led,bool state)
{
U8 andmask;
U8 setmask;
andmask = ~(1 << LEDConfig[led].bit);// a bitmask with all 1's except bit of LED
if (true == state)
{
setmask = (1 << LEDConfig[led].bit); // set bit for LED
} else
{
setmask = 0;
}
GPIOPinWrite(LEDConfig[led].address, andmask, setmask);
}
Of course this is all spelled out; it can be done in a single lines like this:
#DEFINE SETLEDSTATE(led,state) GPIOPinWrite(LEDConfig[led].address, ~(1<<LEDConfig[led].bit),(state<<LEDConfig[led].bit))
this will do the same, but only makes sense when you can dream bit masks, and you only want to toggle some LEDs to debug the real program...
The alternative: bare metal.
In this case you need to set up everything for yourself. For an embedded system, you need to be aware of pin multiplexing and power management (assuming memory controller and cpu clocks are already set up!)
initialization: set pin multiplexing in such a way that the function you want to control is actually mapped on the package.
initialization of pheripheral (in this case either a UART, or a GPIO function on the same pin)
You can't do it using Rx or Tx pins of Serial port. For that you just need to control the RTS or CTS pins of serial port.
Just google for "access COM port in VC++ code" and then control the RTS and CTS status pins to turn ON and OFF any external device.