-
Notifications
You must be signed in to change notification settings - Fork 4
Add ADC Dual Mode support with new AdvancedADCDual class #64
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
7fb56df
44f57bd
7550c29
73b2ac6
888232d
1d11f4f
998716a
4f467e2
e3d00aa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -115,42 +115,73 @@ DMABuffer<Sample> &AdvancedADC::read() { | |||||||||||||||||||
return NULLBUF; | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
int AdvancedADC::begin(uint32_t resolution, uint32_t sample_rate, size_t n_samples, size_t n_buffers) { | ||||||||||||||||||||
int AdvancedADC::begin(uint32_t resolution, uint32_t sample_rate, size_t n_samples, size_t n_buffers,bool do_start,uint8_t adcNum) { | ||||||||||||||||||||
|
||||||||||||||||||||
ADCName instance = ADC_NP; | ||||||||||||||||||||
|
||||||||||||||||||||
// Sanity checks. | ||||||||||||||||||||
if (resolution >= AN_ARRAY_SIZE(ADC_RES_LUT) || (descr && descr->pool)) { | ||||||||||||||||||||
return 0; | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
//if ADC specified is more than the number of available ADC bail out | ||||||||||||||||||||
if(adcNum>AN_ARRAY_SIZE(adc_pin_alt)) | ||||||||||||||||||||
{ | ||||||||||||||||||||
descr = nullptr; | ||||||||||||||||||||
return 0; | ||||||||||||||||||||
} | ||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Spaces between operators, bracket on the same line as function/if. |
||||||||||||||||||||
|
||||||||||||||||||||
// Clear ALTx pin. | ||||||||||||||||||||
for (size_t i=0; i<n_channels; i++) { | ||||||||||||||||||||
adc_pins[i] = (PinName) (adc_pins[i] & ~(ADC_PIN_ALT_MASK)); | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
// Find an ADC that can be used with these set of pins/channels. | ||||||||||||||||||||
for (size_t i=0; instance == ADC_NP && i<AN_ARRAY_SIZE(adc_pin_alt); i++) { | ||||||||||||||||||||
// Calculate alternate function pin. | ||||||||||||||||||||
PinName pin = (PinName) (adc_pins[0] | adc_pin_alt[i]); // First pin decides the ADC. | ||||||||||||||||||||
|
||||||||||||||||||||
// Check if pin is mapped. | ||||||||||||||||||||
if (pinmap_find_peripheral(pin, PinMap_ADC) == NC) { | ||||||||||||||||||||
break; | ||||||||||||||||||||
} | ||||||||||||||||||||
// If ADC not specified find an ADC that can be used with these set of pins/channels. | ||||||||||||||||||||
if(adcNum==0) | ||||||||||||||||||||
{ | ||||||||||||||||||||
for (size_t i=0; instance == ADC_NP && i<AN_ARRAY_SIZE(adc_pin_alt); i++) { | ||||||||||||||||||||
// Calculate alternate function pin. | ||||||||||||||||||||
PinName pin = (PinName) (adc_pins[0] | adc_pin_alt[i]); // First pin decides the ADC. | ||||||||||||||||||||
|
||||||||||||||||||||
// Find the first free ADC according to the available ADCs on pin. | ||||||||||||||||||||
for (size_t j=0; instance == ADC_NP && j<AN_ARRAY_SIZE(adc_descr_all); j++) { | ||||||||||||||||||||
descr = &adc_descr_all[j]; | ||||||||||||||||||||
if (descr->pool == nullptr) { | ||||||||||||||||||||
ADCName tmp_instance = (ADCName) pinmap_peripheral(pin, PinMap_ADC); | ||||||||||||||||||||
if (descr->adc.Instance == ((ADC_TypeDef*) tmp_instance)) { | ||||||||||||||||||||
instance = tmp_instance; | ||||||||||||||||||||
adc_pins[0] = pin; | ||||||||||||||||||||
// Check if pin is mapped. | ||||||||||||||||||||
if (pinmap_find_peripheral(pin, PinMap_ADC) == NC) { | ||||||||||||||||||||
break; | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
// Find the first free ADC according to the available ADCs on pin. | ||||||||||||||||||||
for (size_t j=0; instance == ADC_NP && j<AN_ARRAY_SIZE(adc_descr_all); j++) { | ||||||||||||||||||||
descr = &adc_descr_all[j]; | ||||||||||||||||||||
if (descr->pool == nullptr) { | ||||||||||||||||||||
ADCName tmp_instance = (ADCName) pinmap_peripheral(pin, PinMap_ADC); | ||||||||||||||||||||
if (descr->adc.Instance == ((ADC_TypeDef*) tmp_instance)) { | ||||||||||||||||||||
instance = tmp_instance; | ||||||||||||||||||||
adc_pins[0] = pin; | ||||||||||||||||||||
selectedADC=j; | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
else if(adcNum>0) //if ADC specified use that ADC to try to map first channel | ||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||
{ | ||||||||||||||||||||
PinName pin = (PinName) (adc_pins[0] | adc_pin_alt[adcNum-1]); | ||||||||||||||||||||
|
||||||||||||||||||||
// Check if pin is mapped. | ||||||||||||||||||||
if (pinmap_find_peripheral(pin, PinMap_ADC) == NC) { | ||||||||||||||||||||
return 0; | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
descr = &adc_descr_all[adcNum-1]; | ||||||||||||||||||||
if (descr->pool == nullptr) { | ||||||||||||||||||||
ADCName tmp_instance = (ADCName) pinmap_peripheral(pin, PinMap_ADC); | ||||||||||||||||||||
if (descr->adc.Instance == ((ADC_TypeDef*) tmp_instance)) { | ||||||||||||||||||||
instance = tmp_instance; | ||||||||||||||||||||
adc_pins[0] = pin; | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
selectedADC=adcNum; //Store selected number | ||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
if (instance == ADC_NP) { | ||||||||||||||||||||
// Couldn't find a free ADC/descriptor. | ||||||||||||||||||||
descr = nullptr; | ||||||||||||||||||||
|
@@ -159,11 +190,40 @@ int AdvancedADC::begin(uint32_t resolution, uint32_t sample_rate, size_t n_sampl | |||||||||||||||||||
|
||||||||||||||||||||
// Configure ADC pins. | ||||||||||||||||||||
pinmap_pinout(adc_pins[0], PinMap_ADC); | ||||||||||||||||||||
uint8_t ch_init = 1; | ||||||||||||||||||||
for (size_t i=1; i<n_channels; i++) { | ||||||||||||||||||||
for (size_t j=0; j<AN_ARRAY_SIZE(adc_pin_alt); j++) { | ||||||||||||||||||||
|
||||||||||||||||||||
//If ADC was not specified ensure the remaining channels are mappable to same ADC | ||||||||||||||||||||
if(adcNum==0) | ||||||||||||||||||||
{ | ||||||||||||||||||||
uint8_t ch_init = 1; | ||||||||||||||||||||
for (size_t i=1; i<n_channels; i++) { | ||||||||||||||||||||
for (size_t j=0; j<AN_ARRAY_SIZE(adc_pin_alt); j++) { | ||||||||||||||||||||
// Calculate alternate function pin. | ||||||||||||||||||||
PinName pin = (PinName) (adc_pins[i] | adc_pin_alt[j]); | ||||||||||||||||||||
// Check if pin is mapped. | ||||||||||||||||||||
if (pinmap_find_peripheral(pin, PinMap_ADC) == NC) { | ||||||||||||||||||||
break; | ||||||||||||||||||||
} | ||||||||||||||||||||
// Check if pin is connected to the selected ADC. | ||||||||||||||||||||
if (instance == pinmap_peripheral(pin, PinMap_ADC)) { | ||||||||||||||||||||
pinmap_pinout(pin, PinMap_ADC); | ||||||||||||||||||||
adc_pins[i] = pin; | ||||||||||||||||||||
ch_init++; | ||||||||||||||||||||
break; | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
// All channels must share the same instance; if not, bail out. | ||||||||||||||||||||
if (ch_init < n_channels) { | ||||||||||||||||||||
return 0; | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
else if(adcNum>0) //If specific ADC was requested ensure all other channels map to that same ADC | ||||||||||||||||||||
{ | ||||||||||||||||||||
uint8_t ch_init = 1; | ||||||||||||||||||||
for (size_t i=1; i<n_channels; i++) { | ||||||||||||||||||||
|
||||||||||||||||||||
// Calculate alternate function pin. | ||||||||||||||||||||
PinName pin = (PinName) (adc_pins[i] | adc_pin_alt[j]); | ||||||||||||||||||||
PinName pin = (PinName) (adc_pins[i] | adc_pin_alt[adcNum-1]); | ||||||||||||||||||||
// Check if pin is mapped. | ||||||||||||||||||||
if (pinmap_find_peripheral(pin, PinMap_ADC) == NC) { | ||||||||||||||||||||
break; | ||||||||||||||||||||
|
@@ -173,21 +233,22 @@ int AdvancedADC::begin(uint32_t resolution, uint32_t sample_rate, size_t n_sampl | |||||||||||||||||||
pinmap_pinout(pin, PinMap_ADC); | ||||||||||||||||||||
adc_pins[i] = pin; | ||||||||||||||||||||
ch_init++; | ||||||||||||||||||||
break; | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
// All channels must share the same instance; if not, bail out. | ||||||||||||||||||||
if (ch_init < n_channels) { | ||||||||||||||||||||
return 0; | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
// All channels must share the same instance; if not, bail out. | ||||||||||||||||||||
if (ch_init < n_channels) { | ||||||||||||||||||||
return 0; | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
|
||||||||||||||||||||
|
||||||||||||||||||||
// Allocate DMA buffer pool. | ||||||||||||||||||||
descr->pool = new DMABufferPool<Sample>(n_samples, n_channels, n_buffers); | ||||||||||||||||||||
if (descr->pool == nullptr) { | ||||||||||||||||||||
return 0; | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
//Allocate two DMA buffers for double buffering | ||||||||||||||||||||
descr->dmabuf[0] = descr->pool->allocate(); | ||||||||||||||||||||
descr->dmabuf[1] = descr->pool->allocate(); | ||||||||||||||||||||
|
||||||||||||||||||||
|
@@ -202,7 +263,7 @@ int AdvancedADC::begin(uint32_t resolution, uint32_t sample_rate, size_t n_sampl | |||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
// Link DMA handle to ADC handle, and start the ADC. | ||||||||||||||||||||
__HAL_LINKDMA(&descr->adc, DMA_Handle, descr->dma); | ||||||||||||||||||||
__HAL_LINKDMA(&descr->adc, DMA_Handle, descr->dma); | ||||||||||||||||||||
if (HAL_ADC_Start_DMA(&descr->adc, (uint32_t *) descr->dmabuf[0]->data(), descr->dmabuf[0]->size()) != HAL_OK) { | ||||||||||||||||||||
return 0; | ||||||||||||||||||||
} | ||||||||||||||||||||
|
@@ -212,12 +273,24 @@ int AdvancedADC::begin(uint32_t resolution, uint32_t sample_rate, size_t n_sampl | |||||||||||||||||||
hal_dma_enable_dbm(&descr->dma, descr->dmabuf[0]->data(), descr->dmabuf[1]->data()); | ||||||||||||||||||||
HAL_NVIC_EnableIRQ(descr->dma_irqn); | ||||||||||||||||||||
|
||||||||||||||||||||
if(do_start) | ||||||||||||||||||||
{ | ||||||||||||||||||||
return(start(sample_rate)); | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
No |
||||||||||||||||||||
return 1; | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
int AdvancedADC::start(uint32_t sample_rate) | ||||||||||||||||||||
{ | ||||||||||||||||||||
// Init, config and start the ADC timer. | ||||||||||||||||||||
hal_tim_config(&descr->tim, sample_rate); | ||||||||||||||||||||
|
||||||||||||||||||||
//Start Timer and ADC Capture. If Dual Mode was enabled, then this will also start ADC2 | ||||||||||||||||||||
if (HAL_TIM_Base_Start(&descr->tim) != HAL_OK) { | ||||||||||||||||||||
return 0; | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
return 1; | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
|
@@ -227,11 +300,70 @@ int AdvancedADC::stop() | |||||||||||||||||||
return 1; | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
void AdvancedADC::clear() | ||||||||||||||||||||
{ | ||||||||||||||||||||
descr->pool->flush(); | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
AdvancedADC::~AdvancedADC() | ||||||||||||||||||||
{ | ||||||||||||||||||||
dac_descr_deinit(descr, true); | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
int AdvancedADCDual::begin(AdvancedADC *in1, AdvancedADC *in2,uint32_t resolution, uint32_t sample_rate, size_t n_samples, size_t n_buffers) | ||||||||||||||||||||
{ | ||||||||||||||||||||
adcIN1=in1; | ||||||||||||||||||||
adcIN2=in2; | ||||||||||||||||||||
|
||||||||||||||||||||
int result=0; | ||||||||||||||||||||
|
||||||||||||||||||||
//Configure first pin on ADC1 | ||||||||||||||||||||
result=adcIN1->begin(resolution,sample_rate,n_samples,n_buffers,1,&(adc_pins_unmapped[0]),false,1); | ||||||||||||||||||||
if(result!=1) | ||||||||||||||||||||
{ | ||||||||||||||||||||
return(0); | ||||||||||||||||||||
} | ||||||||||||||||||||
//Configure all other pins on ADC2 | ||||||||||||||||||||
result=adcIN2->begin(resolution,sample_rate,n_samples,n_buffers,n_channels-1,&(adc_pins_unmapped[1]),false,2); | ||||||||||||||||||||
if(result!=1) | ||||||||||||||||||||
{ | ||||||||||||||||||||
return(0); | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
result=hal_enable_dual_mode(); | ||||||||||||||||||||
|
||||||||||||||||||||
result=adcIN1->start(sample_rate); | ||||||||||||||||||||
|
||||||||||||||||||||
if(result!=1) | ||||||||||||||||||||
{ | ||||||||||||||||||||
return(0); | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
return(1); | ||||||||||||||||||||
|
||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
int AdvancedADCDual:: stop() | ||||||||||||||||||||
{ | ||||||||||||||||||||
if(adcIN1!=nullptr) | ||||||||||||||||||||
{ | ||||||||||||||||||||
adcIN1->stop(); | ||||||||||||||||||||
} | ||||||||||||||||||||
if(adcIN2!=nullptr) | ||||||||||||||||||||
{ | ||||||||||||||||||||
adcIN2->stop(); | ||||||||||||||||||||
} | ||||||||||||||||||||
//Always disable dual mode when stopped | ||||||||||||||||||||
int result=hal_disable_dual_mode(); | ||||||||||||||||||||
return(1); | ||||||||||||||||||||
|
||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
AdvancedADCDual::~AdvancedADCDual() | ||||||||||||||||||||
{ | ||||||||||||||||||||
int result=stop(); | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
extern "C" { | ||||||||||||||||||||
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *adc) { | ||||||||||||||||||||
adc_descr_t *descr = adc_descr_get(adc->Instance); | ||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -31,6 +31,8 @@ class AdvancedADC { | |||||||||||
size_t n_channels; | ||||||||||||
adc_descr_t *descr; | ||||||||||||
PinName adc_pins[AN_MAX_ADC_CHANNELS]; | ||||||||||||
bool dualMode; | ||||||||||||
uint8_t selectedADC; | ||||||||||||
|
||||||||||||
public: | ||||||||||||
template <typename ... T> | ||||||||||||
|
@@ -41,21 +43,74 @@ class AdvancedADC { | |||||||||||
for (auto p : {p0, args...}) { | ||||||||||||
adc_pins[n_channels++] = analogPinToPinName(p); | ||||||||||||
} | ||||||||||||
dualMode=false; | ||||||||||||
selectedADC=0; | ||||||||||||
} | ||||||||||||
AdvancedADC(): n_channels(0), descr(nullptr) {} | ||||||||||||
~AdvancedADC(); | ||||||||||||
bool available(); | ||||||||||||
SampleBuffer read(); | ||||||||||||
int begin(uint32_t resolution, uint32_t sample_rate, size_t n_samples, size_t n_buffers); | ||||||||||||
int begin(uint32_t resolution, uint32_t sample_rate, size_t n_samples, size_t n_buffers, size_t n_pins, pin_size_t *pins) { | ||||||||||||
int begin(uint32_t resolution, uint32_t sample_rate, size_t n_samples, size_t n_buffers, bool do_start=true,uint8_t adcNum=0); | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||
int begin(uint32_t resolution, uint32_t sample_rate, size_t n_samples, size_t n_buffers, size_t n_pins, pin_size_t *pins, bool start=true,uint8_t fixed_adc=0) { | ||||||||||||
if (n_pins > AN_MAX_ADC_CHANNELS) n_pins = AN_MAX_ADC_CHANNELS; | ||||||||||||
for (size_t i = 0; i < n_pins; ++i) { | ||||||||||||
adc_pins[i] = analogPinToPinName(pins[i]); | ||||||||||||
} | ||||||||||||
|
||||||||||||
n_channels = n_pins; | ||||||||||||
return begin(resolution, sample_rate, n_samples, n_buffers); | ||||||||||||
return begin(resolution, sample_rate, n_samples, n_buffers,start,fixed_adc); | ||||||||||||
} | ||||||||||||
|
||||||||||||
void clear(); | ||||||||||||
|
||||||||||||
int start(uint32_t sample_rate); | ||||||||||||
|
||||||||||||
//void setADCDualMode(bool dm); | ||||||||||||
//int enableDualMode(); | ||||||||||||
//int disableDualMode(); | ||||||||||||
|
||||||||||||
Comment on lines
+68
to
+72
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||
int stop(); | ||||||||||||
}; | ||||||||||||
|
||||||||||||
class AdvancedADCDual { | ||||||||||||
private: | ||||||||||||
size_t n_channels; | ||||||||||||
pin_size_t adc_pins_unmapped[AN_MAX_ADC_CHANNELS]; | ||||||||||||
AdvancedADC *adcIN1; | ||||||||||||
AdvancedADC *adcIN2; | ||||||||||||
Comment on lines
+80
to
+81
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Those should be passed by reference. |
||||||||||||
public: | ||||||||||||
|
||||||||||||
//For now ADC1 will always be one pin, and ADC2 will sample the rest | ||||||||||||
template <typename ... T> | ||||||||||||
AdvancedADCDual(pin_size_t p0, T ... args):n_channels(0), adcIN1(nullptr), adcIN2(nullptr){ | ||||||||||||
static_assert(sizeof ...(args) < AN_MAX_ADC_CHANNELS+1, | ||||||||||||
"A maximum of 5 channels can be sampled successively."); | ||||||||||||
static_assert (sizeof ...(args) >=2, | ||||||||||||
"At least two channels are required for Dual Mode ADC."); | ||||||||||||
for (auto p : {p0, args...}) { | ||||||||||||
adc_pins_unmapped[n_channels++] = p; | ||||||||||||
} | ||||||||||||
} | ||||||||||||
|
||||||||||||
AdvancedADCDual(): n_channels(0), adcIN1(nullptr), adcIN2(nullptr) | ||||||||||||
{ | ||||||||||||
} | ||||||||||||
~AdvancedADCDual(); | ||||||||||||
|
||||||||||||
int begin(AdvancedADC *in1, AdvancedADC *in2,uint32_t resolution, uint32_t sample_rate, size_t n_samples, size_t n_buffers); | ||||||||||||
int begin(AdvancedADC *in1, AdvancedADC *in2,uint32_t resolution, uint32_t sample_rate, | ||||||||||||
size_t n_samples, size_t n_buffers, size_t n_pins, pin_size_t *pins) { | ||||||||||||
if (n_pins > AN_MAX_ADC_CHANNELS) n_pins = AN_MAX_ADC_CHANNELS; | ||||||||||||
if(n_pins<2) //Cannot run Dual mode with less than two input pins | ||||||||||||
return(0); | ||||||||||||
for (size_t i = 0; i < n_pins; ++i) { | ||||||||||||
adc_pins_unmapped[i] = pins[i]; | ||||||||||||
Serial.println("Pin: "+String(pins[i])); | ||||||||||||
} | ||||||||||||
n_channels = n_pins; | ||||||||||||
return begin(in1, in2, resolution, sample_rate, n_samples, n_buffers); | ||||||||||||
} | ||||||||||||
int stop(); | ||||||||||||
}; | ||||||||||||
|
||||||||||||
#endif /* ARDUINO_ADVANCED_ADC_H_ */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Space between args, and No camel case please.