aboutsummaryrefslogtreecommitdiffstats
path: root/testhal/STM32/STM32F4xx/SPI/main.c
blob: 58ed9cbb9f22e86388b14720b459dc589e15d022 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*
    ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

#include "ch.h"
#include "hal.h"

/*
 * Maximum speed SPI configuration (21MHz, CPHA=0, CPOL=0, MSb first).
 */
static const SPIConfig hs_spicfg = {
  NULL,
  GPIOB,
  12,
  0,
  0
};

/*
 * Low speed SPI configuration (328.125kHz, CPHA=0, CPOL=0, MSb first).
 */
static const SPIConfig ls_spicfg = {
  NULL,
  GPIOB,
  12,
  SPI_CR1_BR_2 | SPI_CR1_BR_1,
  0
};

/*
 * SPI TX and RX buffers.
 */
static uint8_t txbuf[512];
static uint8_t rxbuf[512];

/*
 * SPI bus contender 1.
 */
static THD_WORKING_AREA(spi_thread_1_wa, 256);
static THD_FUNCTION(spi_thread_1, p) {

  (void)p;
  chRegSetThreadName("SPI thread 1");
  while (true) {
    spiAcquireBus(&SPID2);              /* Acquire ownership of the bus.    */
    palSetPad(GPIOD, GPIOD_LED5);       /* LED ON.                          */
    spiStart(&SPID2, &hs_spicfg);       /* Setup transfer parameters.       */
    spiSelect(&SPID2);                  /* Slave Select assertion.          */
    spiExchange(&SPID2, 512,
                txbuf, rxbuf);          /* Atomic transfer operations.      */
    spiUnselect(&SPID2);                /* Slave Select de-assertion.       */
    spiReleaseBus(&SPID2);              /* Ownership release.               */
  }
}

/*
 * SPI bus contender 2.
 */
static THD_WORKING_AREA(spi_thread_2_wa, 256);
static THD_FUNCTION(spi_thread_2, p) {

  (void)p;
  chRegSetThreadName("SPI thread 2");
  while (true) {
    spiAcquireBus(&SPID2);              /* Acquire ownership of the bus.    */
    palClearPad(GPIOD, GPIOD_LED5);     /* LED OFF.                         */
    spiStart(&SPID2, &ls_spicfg);       /* Setup transfer parameters.       */
    spiSelect(&SPID2);                  /* Slave Select assertion.          */
    spiExchange(&SPID2, 512,
                txbuf, rxbuf);          /* Atomic transfer operations.      */
    spiUnselect(&SPID2);                /* Slave Select de-assertion.       */
    spiReleaseBus(&SPID2);              /* Ownership release.               */
  }
}

/*
 * Application entry point.
 */
int main(void) {
  unsigned i;

  /*
   * System initializations.
   * - HAL initialization, this also initializes the configured device drivers
   *   and performs the board-specific initializations.
   * - Kernel initialization, the main() function becomes a thread and the
   *   RTOS is active.
   */
  halInit();
  chSysInit();

  /*
   * SPI2 I/O pins setup.
   */
  palSetPadMode(GPIOB, 13, PAL_MODE_ALTERNATE(5) |
                           PAL_STM32_OSPEED_HIGHEST);       /* New SCK.     */
  palSetPadMode(GPIOB, 14, PAL_MODE_ALTERNATE(5) |
                           PAL_STM32_OSPEED_HIGHEST);       /* New MISO.    */
  palSetPadMode(GPIOB, 15, PAL_MODE_ALTERNATE(5) |
                           PAL_STM32_OSPEED_HIGHEST);       /* New MOSI.    */
  palSetPadMode(GPIOB, 12, PAL_MODE_OUTPUT_PUSHPULL |
                           PAL_STM32_OSPEED_HIGHEST);       /* New CS.      */
  palSetPad(GPIOB, 12);

  /*
   * Prepare transmit pattern.
   */
  for (i = 0; i < sizeof(txbuf); i++)
    txbuf[i] = (uint8_t)i;

  /*
   * Starting the transmitter and receiver threads.
   */
  chThdCreateStatic(spi_thread_1_wa, sizeof(spi_thread_1_wa),
                    NORMALPRIO + 1, spi_thread_1, NULL);
  chThdCreateStatic(spi_thread_2_wa, sizeof(spi_thread_2_wa),
                    NORMALPRIO + 1, spi_thread_2, NULL);

  /*
   * Normal main() thread activity, in this demo it does nothing.
   */
  while (true) {
    chThdSleepMilliseconds(500);
  }
  return 0;
}
n class="o">= (Buttons_GetStatus() & BUTTONS_BUTTON1) ? CurrentWaveValue : 0; #else /* Audio sample is ADC value scaled to fit the entire range */ AudioSample = ((SAMPLE_MAX_RANGE / ADC_MAX_RANGE) * ADC_GetResult()); #if defined(MICROPHONE_BIASED_TO_HALF_RAIL) /* Microphone is biased to half rail voltage, subtract the bias from the sample value */ AudioSample -= (SAMPLE_MAX_RANGE / 2); #endif #endif Audio_Device_WriteSample16(&Microphone_Audio_Interface, AudioSample); } Endpoint_SelectEndpoint(PrevEndpoint); } /** Event handler for the library USB Connection event. */ void EVENT_USB_Device_Connect(void) { LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING); /* Sample reload timer initialization */ TIMSK0 = (1 << OCIE0A); OCR0A = ((F_CPU / 8 / CurrentAudioSampleFrequency) - 1); TCCR0A = (1 << WGM01); // CTC mode TCCR0B = (1 << CS01); // Fcpu/8 speed } /** Event handler for the library USB Disconnection event. */ void EVENT_USB_Device_Disconnect(void) { /* Stop the sample reload timer */ TCCR0B = 0; LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); } /** Event handler for the library USB Configuration Changed event. */ void EVENT_USB_Device_ConfigurationChanged(void) { bool ConfigSuccess = true; ConfigSuccess &= Audio_Device_ConfigureEndpoints(&Microphone_Audio_Interface); LEDs_SetAllLEDs(ConfigSuccess ? LEDMASK_USB_READY : LEDMASK_USB_ERROR); } /** Event handler for the library USB Control Request reception event. */ void EVENT_USB_Device_ControlRequest(void) { Audio_Device_ProcessControlRequest(&Microphone_Audio_Interface); } /** Audio class driver callback for the setting and retrieval of streaming endpoint properties. This callback must be implemented * in the user application to handle property manipulations on streaming audio endpoints. * * When the DataLength parameter is NULL, this callback should only indicate whether the specified operation is valid for * the given endpoint index, and should return as fast as possible. When non-NULL, this value may be altered for GET operations * to indicate the size of the retrieved data. * * \note The length of the retrieved data stored into the Data buffer on GET operations should not exceed the initial value * of the \c DataLength parameter. * * \param[in,out] AudioInterfaceInfo Pointer to a structure containing an Audio Class configuration and state. * \param[in] EndpointProperty Property of the endpoint to get or set, a value from Audio_ClassRequests_t. * \param[in] EndpointAddress Address of the streaming endpoint whose property is being referenced. * \param[in] EndpointControl Parameter of the endpoint to get or set, a value from Audio_EndpointControls_t. * \param[in,out] DataLength For SET operations, the length of the parameter data to set. For GET operations, the maximum * length of the retrieved data. When NULL, the function should return whether the given property * and parameter is valid for the requested endpoint without reading or modifying the Data buffer. * \param[in,out] Data Pointer to a location where the parameter data is stored for SET operations, or where * the retrieved data is to be stored for GET operations. * * \return Boolean \c true if the property get/set was successful, \c false otherwise */ bool CALLBACK_Audio_Device_GetSetEndpointProperty(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo, const uint8_t EndpointProperty, const uint8_t EndpointAddress, const uint8_t EndpointControl, uint16_t* const DataLength, uint8_t* Data) { /* Check the requested endpoint to see if a supported endpoint is being manipulated */ if (EndpointAddress == Microphone_Audio_Interface.Config.DataINEndpoint.Address) { /* Check the requested control to see if a supported control is being manipulated */ if (EndpointControl == AUDIO_EPCONTROL_SamplingFreq) { switch (EndpointProperty) { case AUDIO_REQ_SetCurrent: /* Check if we are just testing for a valid property, or actually adjusting it */ if (DataLength != NULL) { /* Set the new sampling frequency to the value given by the host */ CurrentAudioSampleFrequency = (((uint32_t)Data[2] << 16) | ((uint32_t)Data[1] << 8) | (uint32_t)Data[0]); /* Adjust sample reload timer to the new frequency */ OCR0A = ((F_CPU / 8 / CurrentAudioSampleFrequency) - 1); } return true; case AUDIO_REQ_GetCurrent: /* Check if we are just testing for a valid property, or actually reading it */ if (DataLength != NULL) { *DataLength = 3; Data[2] = (CurrentAudioSampleFrequency >> 16); Data[1] = (CurrentAudioSampleFrequency >> 8); Data[0] = (CurrentAudioSampleFrequency & 0xFF); } return true; } } } return false; } /** Audio class driver callback for the setting and retrieval of streaming interface properties. This callback must be implemented * in the user application to handle property manipulations on streaming audio interfaces. * * When the DataLength parameter is NULL, this callback should only indicate whether the specified operation is valid for * the given entity and should return as fast as possible. When non-NULL, this value may be altered for GET operations * to indicate the size of the retrieved data. * * \note The length of the retrieved data stored into the Data buffer on GET operations should not exceed the initial value * of the \c DataLength parameter. * * \param[in,out] AudioInterfaceInfo Pointer to a structure containing an Audio Class configuration and state. * \param[in] Property Property of the interface to get or set, a value from Audio_ClassRequests_t. * \param[in] EntityAddress Address of the audio entity whose property is being referenced. * \param[in] Parameter Parameter of the entity to get or set, specific to each type of entity (see USB Audio specification). * \param[in,out] DataLength For SET operations, the length of the parameter data to set. For GET operations, the maximum * length of the retrieved data. When NULL, the function should return whether the given property * and parameter is valid for the requested endpoint without reading or modifying the Data buffer. * \param[in,out] Data Pointer to a location where the parameter data is stored for SET operations, or where * the retrieved data is to be stored for GET operations. * * \return Boolean \c true if the property GET/SET was successful, \c false otherwise */ bool CALLBACK_Audio_Device_GetSetInterfaceProperty(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo, const uint8_t Property, const uint8_t EntityAddress, const uint16_t Parameter, uint16_t* const DataLength, uint8_t* Data) { /* No audio interface entities in the device descriptor, thus no properties to get or set. */ return false; }